From 96895e6dae8cf1314f8b4ce3fbab4e7c70ecaf4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 22 Jan 2014 18:59:37 +0200 Subject: [PATCH 1/3] Implement C-based events library for various HTML5 APIs. --- src/library_events.js | 1241 ++++++++++++++++++++++++++++ src/modules.js | 2 +- src/struct_info.json | 184 ++++- system/include/emscripten/events.h | 625 ++++++++++++++ tests/test_browser.py | 2 + tests/test_events.c | 382 +++++++++ 6 files changed, 2434 insertions(+), 2 deletions(-) create mode 100644 src/library_events.js create mode 100644 system/include/emscripten/events.h create mode 100644 tests/test_events.c diff --git a/src/library_events.js b/src/library_events.js new file mode 100644 index 000000000..d1a861277 --- /dev/null +++ b/src/library_events.js @@ -0,0 +1,1241 @@ +var LibraryJsEvents = { + $JsEvents: { + // pointers to structs malloc()ed to Emscripten HEAP for JS->C interop. + keyEvent: 0, + mouseEvent: 0, + wheelEvent: 0, + uiEvent: 0, + focusEvent: 0, + deviceOrientationEvent: 0, + deviceMotionEvent: 0, + fullscreenChangeEvent: 0, + pointerlockChangeEvent: 0, + visibilityChangeEvent: 0, + touchEvent: 0, + + // When the C runtime exits via exit(), we unregister all event handlers added by this library to be nice and clean. + // Track in this field whether we have yet registered that __ATEXIT__ handler. + removeEventListenersRegistered: false, + + registerRemoveEventListeners: function() { + if (!JsEvents.removeEventListenersRegistered) { + __ATEXIT__.push({ func: function() { + for(var i = JsEvents.eventHandlers.length-1; i >= 0; --i) { + JsEvents._removeHandler(i); + } + } }); + JsEvents.removeEventListenersRegistered = true; + } + }, + + findEventTarget: function(target) { + if (target) { + if (typeof target == "number") { + target = Pointer_stringify(target); + } + if (target == '#window') { + return window; + } else if (target == '#document') { + return document; + } else if (target == '#screen') { + return window.screen; + } else if (target == '#canvas') { + return Module['canvas']; + } + if (typeof target == 'string') { + return document.getElementById(target); + } else { + return target; + } + } else { + // The sensible target varies between events, but use window as the default + // since DOM events mostly can default to that. Specific callback registrations + // override their own defaults. + return window; + } + }, + + deferredCalls: [], + + // Queues the given function call to occur the next time we enter an event handler. + // Existing implementations of pointerlock apis have required that + // the target element is active in fullscreen mode first. Thefefore give + // fullscreen mode request a precedence of 1 and pointer lock a precedence of 2 + // and sort by that to always request fullscreen before pointer lock. + deferCall: function(targetFunction, precedence, argsList) { + function arraysHaveEqualContent(arrA, arrB) { + if (arrA.length != arrB.length) { + return false; + } + for(var i in arrA) { + if (arrA[i] != arrB[i]) { + return false; + } + } + return true; + } + // Test if the given call was already queued, and if so, don't add it again. + for(var i in JsEvents.deferredCalls) { + var call = JsEvents.deferredCalls[i]; + if (call.targetFunction == targetFunction && arraysHaveEqualContent(call.argsList, argsList)) { + return; + } + } + JsEvents.deferredCalls.push({ + targetFunction: targetFunction, + precedence: precedence, + argsList: argsList + }); + + JsEvents.deferredCalls.sort(function(x,y) { return x.precedence < y.precedence; }); + }, + + // Erases all deferred calls to the given target function from the queue list. + removeDeferredCalls: function(targetFunction) { + for(var i = 0; i < JsEvents.deferredCalls.length; ++i) { + if (JsEvents.deferredCalls[i].targetFunction == targetFunction) { + JsEvents.deferredCalls.splice(i, 1); + --i; + } + } + }, + + canPerformEventHandlerRequests: function() { + return JsEvents.inEventHandler && JsEvents.currentEventHandler.allowsDeferredCalls; + }, + + runDeferredCalls: function() { + if (!JsEvents.canPerformEventHandlerRequests()) { + return; + } + for(var i = 0; i < JsEvents.deferredCalls.length; ++i) { + var call = JsEvents.deferredCalls[i]; + JsEvents.deferredCalls.splice(i, 1); + --i; + call.targetFunction.apply(this, call.argsList); + } + }, + + // If positive, we are currently executing in a JS event handler. + inEventHandler: 0, + // If we are in an event handler, specifies the event handler object from the eventHandlers array that is currently running. + currentEventHandler: null, + + // Stores objects representing each currently registered JS event handler. + eventHandlers: [], + + _removeHandler: function(i) { + JsEvents.eventHandlers[i].target.removeEventListener(JsEvents.eventHandlers[i].eventTypeString, JsEvents.eventHandlers[i].handlerFunc, true); + JsEvents.eventHandlers.splice(i, 1); + }, + + registerOrRemoveHandler: function(eventHandler) { + var jsEventHandler = function jsEventHandler(event) { + // Increment nesting count for the event handler. + ++JsEvents.inEventHandler; + JsEvents.currentEventHandler = eventHandler; + // Process any old deferred calls the user has placed. + JsEvents.runDeferredCalls(); + // Process the actual event, calls back to user C code handler. + eventHandler.handlerFunc(event); + // Process any new deferred calls that were placed right now from this event handler. + JsEvents.runDeferredCalls(); + // Out of event handler - restore nesting count. + --JsEvents.inEventHandler; + } + + if (eventHandler.callbackfunc) { + eventHandler.target.addEventListener(eventHandler.eventTypeString, jsEventHandler, eventHandler.useCapture); + JsEvents.eventHandlers.push(eventHandler); + JsEvents.registerRemoveEventListeners(); + } else { + for(var i = 0; i < JsEvents.eventHandlers.length; ++i) { + if (JsEvents.eventHandlers[i].target == eventHandler.target + && JsEvents.eventHandlers[i].eventTypeString == eventHandler.eventTypeString) { + JsEvents._removeHandler(i--); + } + } + } + }, + + registerKeyEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JsEvents.keyEvent) { + JsEvents.keyEvent = _malloc( {{{ C_STRUCTS.emscripten_KeyboardEvent.__size__ }}} ); + } + var handlerFunc = function(event) { + var e = event || window.event; + writeStringToMemory(e.key ? e.key : "", JsEvents.keyEvent + {{{ C_STRUCTS.emscripten_KeyboardEvent.key }}} ); + writeStringToMemory(e.code ? e.code : "", JsEvents.keyEvent + {{{ C_STRUCTS.emscripten_KeyboardEvent.code }}} ); + {{{ makeSetValue('JsEvents.keyEvent', C_STRUCTS.emscripten_KeyboardEvent.location, 'e.location', 'i32') }}} + {{{ makeSetValue('JsEvents.keyEvent', C_STRUCTS.emscripten_KeyboardEvent.ctrlKey, 'e.ctrlKey', 'i32') }}} + {{{ makeSetValue('JsEvents.keyEvent', C_STRUCTS.emscripten_KeyboardEvent.shiftKey, 'e.shiftKey', 'i32') }}} + {{{ makeSetValue('JsEvents.keyEvent', C_STRUCTS.emscripten_KeyboardEvent.altKey, 'e.altKey', 'i32') }}} + {{{ makeSetValue('JsEvents.keyEvent', C_STRUCTS.emscripten_KeyboardEvent.metaKey, 'e.metaKey', 'i32') }}} + {{{ makeSetValue('JsEvents.keyEvent', C_STRUCTS.emscripten_KeyboardEvent.repeat, 'e.repeat', 'i32') }}} + writeStringToMemory(e.locale ? e.locale : "", JsEvents.keyEvent + {{{ C_STRUCTS.emscripten_KeyboardEvent.locale }}} ); + writeStringToMemory(e.char ? e.char : "", JsEvents.keyEvent + {{{ C_STRUCTS.emscripten_KeyboardEvent.charValue }}} ); + {{{ makeSetValue('JsEvents.keyEvent', C_STRUCTS.emscripten_KeyboardEvent.charCode, 'e.charCode', 'i32') }}} + {{{ makeSetValue('JsEvents.keyEvent', C_STRUCTS.emscripten_KeyboardEvent.keyCode, 'e.keyCode', 'i32') }}} + {{{ makeSetValue('JsEvents.keyEvent', C_STRUCTS.emscripten_KeyboardEvent.which, 'e.which', 'i32') }}} + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.keyEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JsEvents.findEventTarget(target), + allowsDeferredCalls: true, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JsEvents.registerOrRemoveHandler(eventHandler); + }, + + fillMouseEventData: function(eventStruct, e) { + var rect = Module['canvas'].getBoundingClientRect(); + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.timestamp, 'JsEvents.tick()', 'double') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.screenX, 'e.screenX', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.screenY, 'e.screenY', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.clientX, 'e.clientX', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.clientY, 'e.clientY', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.ctrlKey, 'e.ctrlKey', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.shiftKey, 'e.shiftKey', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.altKey, 'e.altKey', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.metaKey, 'e.metaKey', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.button, 'e.button', 'i16') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.buttons, 'e.buttons', 'i16') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.movementX, 'e.movementX', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.movementY, 'e.movementY', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.canvasX, 'e.clientX - rect.left', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.canvasY, 'e.clientY - rect.top', 'i32') }}} + }, + + registerMouseEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JsEvents.mouseEvent) { + JsEvents.mouseEvent = _malloc( {{{ C_STRUCTS.emscripten_MouseEvent.__size__ }}} ); + } + var handlerFunc = function(event) { + var e = event || window.event; + JsEvents.fillMouseEventData(JsEvents.mouseEvent, e); + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.mouseEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JsEvents.findEventTarget(target), + allowsDeferredCalls: eventTypeString != 'mousemove', // Mouse move events do not allow fullscreen/pointer lock requests to be handled in them! + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JsEvents.registerOrRemoveHandler(eventHandler); + }, + + registerWheelEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JsEvents.wheelEvent) { + JsEvents.wheelEvent = _malloc( {{{ C_STRUCTS.emscripten_WheelEvent.__size__ }}} ); + } + var handlerFunc = function(event) { + var e = event || window.event; + JsEvents.fillMouseEventData(JsEvents.wheelEvent, e); + {{{ makeSetValue('JsEvents.wheelEvent', C_STRUCTS.emscripten_WheelEvent.deltaX, 'e.deltaX', 'double') }}} + {{{ makeSetValue('JsEvents.wheelEvent', C_STRUCTS.emscripten_WheelEvent.deltaY, 'e.deltaY', 'double') }}} + {{{ makeSetValue('JsEvents.wheelEvent', C_STRUCTS.emscripten_WheelEvent.deltaZ, 'e.deltaZ', 'double') }}} + {{{ makeSetValue('JsEvents.wheelEvent', C_STRUCTS.emscripten_WheelEvent.deltaMode, 'e.deltaMode', 'i32') }}} + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.wheelEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JsEvents.findEventTarget(target), + allowsDeferredCalls: true, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JsEvents.registerOrRemoveHandler(eventHandler); + }, + + pageScrollPos: function() { + if (window.pageXOffset > 0 || window.pageYOffset > 0) { + return [window.pageXOffset, window.pageYOffset]; + } + if (document.documentElement.scrollLeft > 0 || document.documentElement.scrollTop > 0) { + return [document.documentElement.scrollLeft, document.documentElement.scrollTop]; + } + return [document.body.scrollLeft|0, document.body.scrollTop|0]; + }, + + registerUiEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JsEvents.uiEvent) { + JsEvents.uiEvent = _malloc( {{{ C_STRUCTS.emscripten_UiEvent.__size__ }}} ); + } + + if (eventTypeString == "scroll" && !target) { + target = document; // By default read scroll events on document rather than window. + } else { + target = JsEvents.findEventTarget(target); + } + + var handlerFunc = function(event) { + var e = event || window.event; + if (e.target != target) { + // Never take ui events such as scroll via a 'bubbled' route, but always from the direct element that + // was targeted. Otherwise e.g. if app logs a message in response to a page scroll, the Emscripten log + // message box could cause to scroll, generating a new (bubbled) scroll message, causing a new log print, + // causing a new scroll, etc.. + return; + } + var scrollPos = JsEvents.pageScrollPos(); + {{{ makeSetValue('JsEvents.uiEvent', C_STRUCTS.emscripten_UiEvent.detail, 'e.detail', 'i32') }}} + {{{ makeSetValue('JsEvents.uiEvent', C_STRUCTS.emscripten_UiEvent.documentBodyClientWidth, 'document.body.clientWidth', 'i32') }}} + {{{ makeSetValue('JsEvents.uiEvent', C_STRUCTS.emscripten_UiEvent.documentBodyClientHeight, 'document.body.clientHeight', 'i32') }}} + {{{ makeSetValue('JsEvents.uiEvent', C_STRUCTS.emscripten_UiEvent.windowInnerWidth, 'window.innerWidth', 'i32') }}} + {{{ makeSetValue('JsEvents.uiEvent', C_STRUCTS.emscripten_UiEvent.windowInnerHeight, 'window.innerHeight', 'i32') }}} + {{{ makeSetValue('JsEvents.uiEvent', C_STRUCTS.emscripten_UiEvent.windowOuterWidth, 'window.outerWidth', 'i32') }}} + {{{ makeSetValue('JsEvents.uiEvent', C_STRUCTS.emscripten_UiEvent.windowOuterHeight, 'window.outerHeight', 'i32') }}} + {{{ makeSetValue('JsEvents.uiEvent', C_STRUCTS.emscripten_UiEvent.scrollTop, 'scrollPos[0]', 'i32') }}} + {{{ makeSetValue('JsEvents.uiEvent', C_STRUCTS.emscripten_UiEvent.scrollLeft, 'scrollPos[1]', 'i32') }}} + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.uiEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: target, + allowsDeferredCalls: false, // Neither scroll or resize events allow running requests inside them. + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JsEvents.registerOrRemoveHandler(eventHandler); + }, + + getNodeNameForTarget: function(target) { + if (!target) { + return ''; + } + if (target == window) { + return '#window'; + } + if (target == window.screen) { + return '#screen'; + } + return (target && target.nodeName) ? target.nodeName : ''; + }, + + registerFocusEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JsEvents.focusEvent) { + JsEvents.focusEvent = _malloc( {{{ C_STRUCTS.emscripten_FocusEvent.__size__ }}} ); + } + var handlerFunc = function(event) { + var e = event || window.event; + + var nodeName = JsEvents.getNodeNameForTarget(e.target); + var id = e.target.id ? e.target.id : ''; + writeStringToMemory(nodeName, JsEvents.focusEvent + {{{ C_STRUCTS.emscripten_FocusEvent.nodeName }}} ); + writeStringToMemory(id, JsEvents.focusEvent + {{{ C_STRUCTS.emscripten_FocusEvent.id }}} ); + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.focusEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JsEvents.findEventTarget(target), + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JsEvents.registerOrRemoveHandler(eventHandler); + }, + + tick: function() { + if (window['performance'] && window['performance']['now']) { + return window['performance']['now'](); + } else { + return Date.now(); + } + }, + + registerDeviceOrientationEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JsEvents.deviceOrientationEvent) { + JsEvents.deviceOrientationEvent = _malloc( {{{ C_STRUCTS.emscripten_DeviceOrientationEvent.__size__ }}} ); + } + var handlerFunc = function(event) { + var e = event || window.event; + + {{{ makeSetValue('JsEvents.deviceOrientationEvent', C_STRUCTS.emscripten_DeviceOrientationEvent.timestamp, 'JsEvents.tick()', 'double') }}} + {{{ makeSetValue('JsEvents.deviceOrientationEvent', C_STRUCTS.emscripten_DeviceOrientationEvent.alpha, 'e.alpha', 'double') }}} + {{{ makeSetValue('JsEvents.deviceOrientationEvent', C_STRUCTS.emscripten_DeviceOrientationEvent.beta, 'e.beta', 'double') }}} + {{{ makeSetValue('JsEvents.deviceOrientationEvent', C_STRUCTS.emscripten_DeviceOrientationEvent.gamma, 'e.gamma', 'double') }}} + {{{ makeSetValue('JsEvents.deviceOrientationEvent', C_STRUCTS.emscripten_DeviceOrientationEvent.absolute, 'e.absolute', 'i32') }}} + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.deviceOrientationEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JsEvents.findEventTarget(target), + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JsEvents.registerOrRemoveHandler(eventHandler); + }, + + registerDeviceMotionEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JsEvents.deviceMotionEvent) { + JsEvents.deviceMotionEvent = _malloc( {{{ C_STRUCTS.emscripten_DeviceMotionEvent.__size__ }}} ); + } + var handlerFunc = function(event) { + var e = event || window.event; + + {{{ makeSetValue('JsEvents.deviceOrientationEvent', C_STRUCTS.emscripten_DeviceMotionEvent.timestamp, 'JsEvents.tick()', 'double') }}} + {{{ makeSetValue('JsEvents.deviceMotionEvent', C_STRUCTS.emscripten_DeviceMotionEvent.accelerationX, 'e.acceleration.x', 'double') }}} + {{{ makeSetValue('JsEvents.deviceMotionEvent', C_STRUCTS.emscripten_DeviceMotionEvent.accelerationY, 'e.acceleration.y', 'double') }}} + {{{ makeSetValue('JsEvents.deviceMotionEvent', C_STRUCTS.emscripten_DeviceMotionEvent.accelerationZ, 'e.acceleration.z', 'double') }}} + {{{ makeSetValue('JsEvents.deviceMotionEvent', C_STRUCTS.emscripten_DeviceMotionEvent.accelerationIncludingGravityX, 'e.accelerationIncludingGravity.x', 'double') }}} + {{{ makeSetValue('JsEvents.deviceMotionEvent', C_STRUCTS.emscripten_DeviceMotionEvent.accelerationIncludingGravityY, 'e.accelerationIncludingGravity.y', 'double') }}} + {{{ makeSetValue('JsEvents.deviceMotionEvent', C_STRUCTS.emscripten_DeviceMotionEvent.accelerationIncludingGravityZ, 'e.accelerationIncludingGravity.z', 'double') }}} + {{{ makeSetValue('JsEvents.deviceMotionEvent', C_STRUCTS.emscripten_DeviceMotionEvent.rotationRateAlpha, 'e.rotationRate.alpha', 'double') }}} + {{{ makeSetValue('JsEvents.deviceMotionEvent', C_STRUCTS.emscripten_DeviceMotionEvent.rotationRateBeta, 'e.rotationRate.beta', 'double') }}} + {{{ makeSetValue('JsEvents.deviceMotionEvent', C_STRUCTS.emscripten_DeviceMotionEvent.rotationRateGamma, 'e.rotationRate.gamma', 'double') }}} + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.deviceMotionEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JsEvents.findEventTarget(target), + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JsEvents.registerOrRemoveHandler(eventHandler); + }, + + fillOrientationChangeEventData: function(eventStruct, e) { + var orientations = ["portrait-primary", "portrait-secondary", "landscape-primary", "landscape-secondary"]; + var orientations2 = ["portrait", "portrait", "landscape", "landscape"]; + + var orientationString = window.screen.orientation || window.screen.mozOrientation; + var orientation = orientations.indexOf(orientationString); + if (orientation == -1) { + orientation = orientations2.indexOf(orientationString); + } + + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_OrientationChangeEvent.orientationIndex, '1 << orientation', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_OrientationChangeEvent.orientationAngle, 'window.orientation', 'i32') }}} + }, + + registerOrientationChangeEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JsEvents.orientationChangeEvent) { + JsEvents.orientationChangeEvent = _malloc( {{{ C_STRUCTS.emscripten_OrientationChangeEvent.__size__ }}} ); + } + + if (!target) { + target = window.screen; // Orientation events need to be captured from 'window.screen' instead of 'window' + } else { + target = JsEvents.findEventTarget(target); + } + + var handlerFunc = function(event) { + var e = event || window.event; + + JsEvents.fillOrientationChangeEventData(JsEvents.orientationChangeEvent, e); + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.orientationChangeEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + if (eventTypeString == "orientationchange" && window.screen.mozOrientation !== undefined) { + eventTypeString = "mozorientationchange"; + } + + var eventHandler = { + target: target, + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JsEvents.registerOrRemoveHandler(eventHandler); + }, + + fillFullscreenChangeEventData: function(eventStruct, e) { + var fullscreenElement = document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement; + var isFullscreen = !!fullscreenElement; + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_FullscreenChangeEvent.isFullscreen, 'isFullscreen', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_FullscreenChangeEvent.fullscreenEnabled, 'document.fullscreenEnabled', 'i32') }}} + var nodeName = JsEvents.getNodeNameForTarget(fullscreenElement); + var id = (fullscreenElement && fullscreenElement.id) ? fullscreenElement.id : ''; + writeStringToMemory(nodeName, eventStruct + {{{ C_STRUCTS.emscripten_FullscreenChangeEvent.nodeName }}} ); + writeStringToMemory(id, eventStruct + {{{ C_STRUCTS.emscripten_FullscreenChangeEvent.id }}} ); + }, + + registerFullscreenChangeEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JsEvents.fullscreenChangeEvent) { + JsEvents.fullscreenChangeEvent = _malloc( {{{ C_STRUCTS.emscripten_FullscreenChangeEvent.__size__ }}} ); + } + + if (!target) { + target = document; // Fullscreen change events need to be captured from 'document' by default instead of 'window' + } else { + target = JsEvents.findEventTarget(target); + } + + var handlerFunc = function(event) { + var e = event || window.event; + + JsEvents.fillFullscreenChangeEventData(JsEvents.fullscreenChangeEvent, e); + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.fullscreenChangeEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: target, + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JsEvents.registerOrRemoveHandler(eventHandler); + }, + + requestFullscreen: function(target) { + if (target.requestFullscreen) { + target.requestFullscreen(); + } else if (target.msRequestFullscreen) { + target.msRequestFullscreen(); + } else if (target.mozRequestFullScreen) { + target.mozRequestFullScreen(); + } else if (target.webkitRequestFullscreen) { + target.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); + } else { + return 2 /* Target does not support requesting fullscreen */; + } + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + fillPointerlockChangeEventData: function(eventStruct, e) { + var pointerLockElement = document.pointerLockElement || document.mozPointerLockElement || document.webkitPointerLockElement || document.msPointerLockElement; + var isPointerlocked = !!pointerLockElement; + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_PointerlockChangeEvent.isActive, 'isPointerlocked', 'i32') }}} + var nodeName = JsEvents.getNodeNameForTarget(pointerLockElement); + var id = (pointerLockElement && pointerLockElement.id) ? pointerLockElement.id : ''; + writeStringToMemory(nodeName, eventStruct + {{{ C_STRUCTS.emscripten_PointerlockChangeEvent.nodeName }}} ); + writeStringToMemory(id, eventStruct + {{{ C_STRUCTS.emscripten_PointerlockChangeEvent.id }}}); + }, + + registerPointerlockChangeEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JsEvents.pointerlockChangeEvent) { + JsEvents.pointerlockChangeEvent = _malloc( {{{ C_STRUCTS.emscripten_PointerlockChangeEvent.__size__ }}} ); + } + + if (!target) { + target = document; // Pointer lock change events need to be captured from 'document' by default instead of 'window' + } else { + target = JsEvents.findEventTarget(target); + } + + var handlerFunc = function(event) { + var e = event || window.event; + + JsEvents.fillPointerlockChangeEventData(JsEvents.pointerlockChangeEvent, e); + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.pointerlockChangeEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: target, + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JsEvents.registerOrRemoveHandler(eventHandler); + }, + + requestPointerLock: function(target) { + if (target.requestPointerLock) { + target.requestPointerLock(); + } else if (target.mozRequestPointerLock) { + target.mozRequestPointerLock(); + } else if (target.webkitRequestPointerLock) { + target.webkitRequestPointerLock(); + } else if (target.msRequestPointerLock) { + target.msRequestPointerLock(); + } else { + return 2 /* Target does not support requesting pointer lock */; + } + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + fillVisibilityChangeEventData: function(eventStruct, e) { + var visibilityStates = [ "hidden", "visible", "prerender", "unloaded" ]; + var visibilityState = visibilityStates.indexOf(document.visibilityState); + + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_VisibilityChangeEvent.hidden, 'document.hidden', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_VisibilityChangeEvent.visibilityState, 'visibilityState', 'i32') }}} + }, + + registerVisibilityChangeEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JsEvents.visibilityChangeEvent) { + JsEvents.visibilityChangeEvent = _malloc( {{{ C_STRUCTS.emscripten_VisibilityChangeEvent.__size__ }}} ); + } + + if (!target) { + target = document; // Visibility change events need to be captured from 'document' by default instead of 'window' + } else { + target = JsEvents.findEventTarget(target); + } + + var handlerFunc = function(event) { + var e = event || window.event; + + JsEvents.fillVisibilityChangeEventData(JsEvents.visibilityChangeEvent, e); + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.visibilityChangeEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: target, + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JsEvents.registerOrRemoveHandler(eventHandler); + }, + + registerTouchEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JsEvents.touchEvent) { + JsEvents.touchEvent = _malloc( {{{ C_STRUCTS.emscripten_TouchEvent.__size__ }}} ); + } + + var handlerFunc = function(event) { + var e = event || window.event; + + var touches = {}; + for(var i = 0; i < e.touches.length; ++i) { + var touch = e.touches[i]; + touches[touch.identifier] = touch; + } + for(var i = 0; i < e.changedTouches.length; ++i) { + var touch = e.changedTouches[i]; + touches[touch.identifier] = touch; + touch.changed = true; + } + for(var i = 0; i < e.targetTouches.length; ++i) { + var touch = e.targetTouches[i]; + touches[touch.identifier].onTarget = true; + } + + var ptr = JsEvents.touchEvent; + {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchEvent.ctrlKey, 'e.ctrlKey', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchEvent.shiftKey, 'e.shiftKey', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchEvent.altKey, 'e.altKey', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchEvent.metaKey, 'e.metaKey', 'i32') }}} + ptr += {{{ C_STRUCTS.emscripten_TouchEvent.touches }}}; // Advance to the start of the touch array. + var rect = Module['canvas'].getBoundingClientRect(); + var numTouches = 0; + for(var i in touches) { + var t = touches[i]; + {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.identifier, 't.identifier', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.screenX, 't.screenX', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.screenY, 't.screenY', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.clientX, 't.clientX', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.clientY, 't.clientY', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.pageX, 't.pageX', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.pageY, 't.pageY', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.isChanged, 't.changed', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.onTarget, 't.onTarget', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.canvasX, 't.clientX - rect.left', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.canvasY, 't.clientY - rect.top', 'i32') }}} + ptr += {{{ C_STRUCTS.emscripten_TouchPoint.__size__ }}}; + + if (++numTouches >= 32) { + break; + } + } + {{{ makeSetValue('JsEvents.touchEvent', C_STRUCTS.emscripten_TouchEvent.numTouches, 'numTouches', 'i32') }}} + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.touchEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JsEvents.findEventTarget(target), + allowsDeferredCalls: true, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JsEvents.registerOrRemoveHandler(eventHandler); + }, + + fillGamepadEventData: function(eventStruct, e) { + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_GamepadEvent.timestamp, 'e.timestamp', 'double') }}} + for(var i = 0; i < e.axes.length; ++i) { + {{{ makeSetValue('eventStruct+i*8', C_STRUCTS.emscripten_GamepadEvent.axis, 'e.axes[i]', 'double') }}} + } + for(var i = 0; i < e.buttons.length; ++i) { + {{{ makeSetValue('eventStruct+i*8', C_STRUCTS.emscripten_GamepadEvent.analogButton, 'e.buttons[i].value', 'double') }}} + } + for(var i = 0; i < e.buttons.length; ++i) { + {{{ makeSetValue('eventStruct+i*4', C_STRUCTS.emscripten_GamepadEvent.digitalButton, 'e.buttons[i].pressed', 'i32') }}} + } + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_GamepadEvent.connected, 'e.connected', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_GamepadEvent.index, 'e.index', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_GamepadEvent.numAxes, 'e.axes.length', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_GamepadEvent.numButtons, 'e.buttons.length', 'i32') }}} + writeStringToMemory(e.id, eventStruct + {{{ C_STRUCTS.emscripten_GamepadEvent.id }}} ); + writeStringToMemory(e.mapping, eventStruct + {{{ C_STRUCTS.emscripten_GamepadEvent.mapping }}} ); + }, + + registerGamepadEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JsEvents.gamepadEvent) { + JsEvents.gamepadEvent = _malloc( {{{ C_STRUCTS.emscripten_GamepadEvent.__size__ }}} ); + } + + var handlerFunc = function(event) { + var e = event || window.event; + + JsEvents.fillGamepadEventData(JsEvents.gamepadEvent, e.gamepad); + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.gamepadEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JsEvents.findEventTarget(target), + allowsDeferredCalls: true, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JsEvents.registerOrRemoveHandler(eventHandler); + }, + + registerBeforeUnloadEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + var handlerFunc = function(event) { + var e = event || window.event; + + var confirmationMessage = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, 0, userData]); + + confirmationMessage = Pointer_stringify(confirmationMessage); + if (confirmationMessage) { + e.preventDefault(); + e.returnValue = confirmationMessage; + return confirmationMessage; + } + }; + + var eventHandler = { + target: JsEvents.findEventTarget(target), + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JsEvents.registerOrRemoveHandler(eventHandler); + }, + + battery: function() { return navigator.battery || navigator.mozBattery || navigator.webkitBattery; }, + + fillBatteryEventData: function(eventStruct, e) { + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_BatteryEvent.chargingTime, 'e.chargingTime', 'double') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_BatteryEvent.dischargingTime, 'e.dischargingTime', 'double') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_BatteryEvent.level, 'e.level', 'double') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_BatteryEvent.charging, 'e.charging', 'i32') }}} + }, + + registerBatteryEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JsEvents.batteryEvent) { + JsEvents.batteryEvent = _malloc( {{{ C_STRUCTS.emscripten_BatteryEvent.__size__ }}} ); + } + + var handlerFunc = function(event) { + var e = event || window.event; + + JsEvents.fillBatteryEventData(JsEvents.batteryEvent, JsEvents.battery()); + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.batteryEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JsEvents.findEventTarget(target), + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JsEvents.registerOrRemoveHandler(eventHandler); + }, + + registerWebGlEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!target) { + target = Module['canvas']; + } + var handlerFunc = function(event) { + var e = event || window.event; + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, 0, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JsEvents.findEventTarget(target), + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JsEvents.registerOrRemoveHandler(eventHandler); + }, + }, + + emscripten_set_keypress_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_KEYPRESS') }}}, "keypress"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_keydown_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_KEYDOWN') }}}, "keydown"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_keyup_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_KEYUP') }}}, "keyup"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_click_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_CLICK') }}}, "click"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_mousedown_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEDOWN') }}}, "mousedown"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_mouseup_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEUP') }}}, "mouseup"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_dblclick_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_DBLCLICK') }}}, "dblclick"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_mousemove_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEMOVE') }}}, "mousemove"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_get_mouse_status: function(mouseState) { + if (!JsEvents.mouseEvent) { + return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; + } + // HTML5 does not really have a polling API for mouse events, so implement one manually by + // returning the data from the most recently received event. This requires that user has registered + // at least some no-op function as an event handler to any of the mouse function. + HEAP32.set(HEAP32.subarray(JsEvents.mouseEvent, {{{ C_STRUCTS.emscripten_MouseEvent.__size__ }}}), mouseState); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_wheel_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerWheelEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WHEEL') }}}, "wheel"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_resize_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_RESIZE') }}}, "resize"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_scroll_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_SCROLL') }}}, "scroll"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_blur_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BLUR') }}}, "blur"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_focus_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FOCUS') }}}, "focus"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_focusin_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FOCUSIN') }}}, "focusin"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_focusout_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FOCUSOUT') }}}, "focusout"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_deviceorientation_callback: function(userData, useCapture, callbackfunc) { + JsEvents.registerDeviceOrientationEventCallback(window, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_DEVICEORIENTATION') }}}, "deviceorientation"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_get_deviceorientation_status: function(orientationState) { + if (!JsEvents.deviceOrientationEvent) { + return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; + } + // HTML5 does not really have a polling API for device orientation events, so implement one manually by + // returning the data from the most recently received event. This requires that user has registered + // at least some no-op function as an event handler. + HEAP32.set(HEAP32.subarray(JsEvents.deviceOrientationEvent, {{{ C_STRUCTS.emscripten_DeviceOrientationEvent.__size__ }}}), orientationState); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_devicemotion_callback: function(userData, useCapture, callbackfunc) { + JsEvents.registerDeviceMotionEventCallback(window, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_DEVICEMOTION') }}}, "devicemotion"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_get_devicemotion_status: function(motionState) { + if (!JsEvents.deviceMotionEvent) { + return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; + } + // HTML5 does not really have a polling API for device motion events, so implement one manually by + // returning the data from the most recently received event. This requires that user has registered + // at least some no-op function as an event handler. + HEAP32.set(HEAP32.subarray(JsEvents.deviceMotionEvent, {{{ C_STRUCTS.emscripten_DeviceMotionEvent.__size__ }}}), motionState); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_orientationchange_callback: function(userData, useCapture, callbackfunc) { + if (!window.screen || !window.screen.addEventListener) { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + JsEvents.registerOrientationChangeEventCallback(window.screen, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_ORIENTATIONCHANGE') }}}, "orientationchange"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_get_orientation_status: function(orientationChangeEvent) { + JsEvents.fillOrientationChangeEventData(orientationChangeEvent); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_lock_orientation: function(allowedOrientations) { + var orientations = []; + if (allowedOrientations & 1) orientations.push("portrait-primary"); + if (allowedOrientations & 2) orientations.push("portrait-secondary"); + if (allowedOrientations & 4) orientations.push("landscape-primary"); + if (allowedOrientations & 8) orientations.push("landscape-secondary"); + if (window.screen.lockOrientation) { + window.screen.lockOrientation(orientations); + } else if (window.screen.mozLockOrientation) { + window.screen.mozLockOrientation(orientations); + } else if (window.screen.webkitLockOrientation) { + window.screen.webkitLockOrientation(orientations); + } else if (window.screen.msLockOrientation) { + window.screen.msLockOrientation(orientations); + } else { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_unlock_orientation: function() { + if (window.screen.unlockOrientation) { + window.screen.unlockOrientation(); + } else if (window.screen.mozUnlockOrientation) { + window.screen.mozUnlockOrientation(); + } else if (window.screen.webkitUnlockOrientation) { + window.screen.webkitUnlockOrientation(); + } else if (window.screen.msUnlockOrientation) { + window.screen.msUnlockOrientation(); + } else { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_fullscreenchange_callback: function(userData, useCapture, callbackfunc) { + JsEvents.registerFullscreenChangeEventCallback(userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FULLSCREENCHANGE') }}}, "fullscreenchange"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_get_fullscreen_status: function(fullscreenStatus) { + JsEvents.fillFullscreenChangeEventData(fullscreenStatus); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + // https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Using_full_screen_mode + emscripten_request_fullscreen: function(target, deferUntilInEventHandler) { + if (!target) { + target = '#canvas'; + } + target = JsEvents.findEventTarget(target); + if (!target) { + return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + } + + if (!target.requestFullscreen && !target.msRequestFullscreen && !target.mozRequestFullScreen && !target.webkitRequestFullscreen) { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + + var canPerformRequests = JsEvents.canPerformEventHandlerRequests(); + + // Queue this function call if we're not currently in an event handler and the user saw it appropriate to do so. + if (!canPerformRequests) { + if (deferUntilInEventHandler) { + JsEvents.deferCall(JsEvents.requestFullscreen, 1 /* priority over pointer lock */, [target]); + return {{{ cDefine('EMSCRIPTEN_RESULT_DEFERRED') }}}; + } else { + return {{{ cDefine('EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED') }}}; + } + } + + return JsEvents.requestFullscreen(target); + }, + + emscripten_exit_fullscreen: function() { + // Make sure no queued up calls will fire after this. + JsEvents.removeDeferredCalls(JsEvents.requestFullscreen); + + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.msExitFullscreen) { + document.msExitFullscreen(); + } else if (document.mozCancelFullScreen) { + document.mozCancelFullScreen(); + } else if (document.webkitExitFullscreen) { + document.webkitExitFullscreen(); + } else { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_pointerlockchange_callback: function(userData, useCapture, callbackfunc) { + JsEvents.registerPointerlockChangeEventCallback(document, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKCHANGE') }}}, "pointerlockchange"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_get_pointerlock_status: function(pointerlockStatus) { + JsEvents.fillPointerlockChangeEventData(pointerlockStatus); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_request_pointerlock: function(target, deferUntilInEventHandler) { + if (!target) { + target = '#canvas'; + } + target = JsEvents.findEventTarget(target); + if (!target) { + return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + } + if (!target.requestPointerLock && !target.mozRequestPointerLock && !target.webkitRequestPointerLock && !target.msRequestPointerLock) { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + + var canPerformRequests = JsEvents.canPerformEventHandlerRequests(); + + // Queue this function call if we're not currently in an event handler and the user saw it appropriate to do so. + if (!canPerformRequests) { + if (deferUntilInEventHandler) { + JsEvents.deferCall(JsEvents.requestPointerLock, 2 /* priority below fullscreen */, [target]); + return {{{ cDefine('EMSCRIPTEN_RESULT_DEFERRED') }}}; + } else { + return {{{ cDefine('EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED') }}}; + } + } + + return JsEvents.requestPointerLock(target); + }, + + emscripten_exit_pointerlock: function() { + // Make sure no queued up calls will fire after this. + JsEvents.removeDeferredCalls(JsEvents.requestPointerLock); + + if (document.exitPointerLock) { + document.exitPointerLock(); + } else if (document.msExitPointerLock) { + document.msExitPointerLock(); + } else if (document.mozExitPointerLock) { + document.mozExitPointerLock(); + } else if (document.webkitExitPointerLock) { + document.webkitExitPointerLock(); + } else { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_vibrate: function(msecs) { + if (!navigator.vibrate) { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + + navigator.vibrate(msecs); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_vibrate_pattern: function(msecsArray, numEntries) { + if (!navigator.vibrate) { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + + var vibrateList = []; + for(var i = 0; i < numEntries; ++i) { + var msecs = {{{ makeGetValue('msecsArray', 'i*4', 'i32') }}} + vibrateList.push(msecs); + } + navigator.vibrate(vibrateList); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_visibilitychange_callback: function(userData, useCapture, callbackfunc) { + JsEvents.registerVisibilityChangeEventCallback(document, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_VISIBILITYCHANGE') }}}, "visibilitychange"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_get_visibility_status: function(visibilityStatus) { + JsEvents.fillVisibilityChangeEventData(visibilityStatus); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_touchstart_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHSTART') }}}, "touchstart"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_touchend_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHEND') }}}, "touchend"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_touchmove_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHMOVE') }}}, "touchmove"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_touchcancel_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHCANCEL') }}}, "touchcancel"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_gamepadconnected_callback: function(userData, useCapture, callbackfunc) { + JsEvents.registerGamepadEventCallback(window, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_GAMEPADCONNECTED') }}}, "gamepadconnected"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_gamepaddisconnected_callback: function(userData, useCapture, callbackfunc) { + JsEvents.registerGamepadEventCallback(window, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED') }}}, "gamepaddisconnected"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_get_num_gamepads: function() { + if (!navigator.getGamepads) { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + return navigator.getGamepads().length; + }, + + emscripten_get_gamepad_status: function(index, gamepadState) { + if (!navigator.getGamepads) { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + var gamepads = navigator.getGamepads(); + if (index < 0 || index >= gamepads.length) { + return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; + } + JsEvents.fillGamepadEventData(gamepadState, gamepads[index]); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_beforeunload_callback: function(userData, callbackfunc) { + JsEvents.registerBeforeUnloadEventCallback(window, userData, true, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BEFOREUNLOAD') }}}, "beforeunload"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_batterychargingchange_callback: function(userData, callbackfunc) { + JsEvents.registerBatteryEventCallback(JsEvents.battery(), userData, true, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE') }}}, "chargingchange"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_batterylevelchange_callback: function(userData, callbackfunc) { + JsEvents.registerBatteryEventCallback(JsEvents.battery(), userData, true, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE') }}}, "levelchange"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_get_battery_status: function(batteryState) { + JsEvents.fillBatteryEventData(batteryState, JsEvents.battery()); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_webglcontextlost_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST') }}}, "webglcontextlost"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_webglcontextrestored_callback: function(target, userData, useCapture, callbackfunc) { + JsEvents.registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED') }}}, "webglcontextrestored"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, +}; + +autoAddDeps(LibraryJsEvents, '$JsEvents'); +mergeInto(LibraryManager.library, LibraryJsEvents); diff --git a/src/modules.js b/src/modules.js index ad467ba76..7b267971f 100644 --- a/src/modules.js +++ b/src/modules.js @@ -424,7 +424,7 @@ var LibraryManager = { load: function() { if (this.library) return; - var libraries = ['library.js', 'library_path.js', 'library_fs.js', 'library_idbfs.js', 'library_memfs.js', 'library_nodefs.js', 'library_sockfs.js', 'library_tty.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js', 'library_uuid.js', 'library_glew.js'].concat(additionalLibraries); + var libraries = ['library.js', 'library_path.js', 'library_fs.js', 'library_idbfs.js', 'library_memfs.js', 'library_nodefs.js', 'library_sockfs.js', 'library_tty.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js', 'library_uuid.js', 'library_glew.js', 'library_events.js'].concat(additionalLibraries); for (var i = 0; i < libraries.length; i++) { eval(processMacros(preprocess(read(libraries[i])))); } diff --git a/src/struct_info.json b/src/struct_info.json index a22851b62..ec4490974 100644 --- a/src/struct_info.json +++ b/src/struct_info.json @@ -1073,5 +1073,187 @@ "UUID_TYPE_DCE_RANDOM" ], "structs": {} + }, + // =========================================== + // emscripten events library + // =========================================== + { + "file": "emscripten/events.h", + "defines": [ + "EMSCRIPTEN_EVENT_KEYPRESS", + "EMSCRIPTEN_EVENT_KEYDOWN", + "EMSCRIPTEN_EVENT_KEYUP", + "EMSCRIPTEN_EVENT_CLICK", + "EMSCRIPTEN_EVENT_MOUSEDOWN", + "EMSCRIPTEN_EVENT_MOUSEUP", + "EMSCRIPTEN_EVENT_DBLCLICK", + "EMSCRIPTEN_EVENT_MOUSEMOVE", + "EMSCRIPTEN_EVENT_WHEEL", + "EMSCRIPTEN_EVENT_RESIZE", + "EMSCRIPTEN_EVENT_SCROLL", + "EMSCRIPTEN_EVENT_BLUR", + "EMSCRIPTEN_EVENT_FOCUS", + "EMSCRIPTEN_EVENT_FOCUSIN", + "EMSCRIPTEN_EVENT_FOCUSOUT", + "EMSCRIPTEN_EVENT_DEVICEORIENTATION", + "EMSCRIPTEN_EVENT_DEVICEMOTION", + "EMSCRIPTEN_EVENT_ORIENTATIONCHANGE", + "EMSCRIPTEN_EVENT_FULLSCREENCHANGE", + "EMSCRIPTEN_EVENT_POINTERLOCKCHANGE", + "EMSCRIPTEN_EVENT_VISIBILITYCHANGE", + "EMSCRIPTEN_EVENT_TOUCHSTART", + "EMSCRIPTEN_EVENT_TOUCHEND", + "EMSCRIPTEN_EVENT_TOUCHMOVE", + "EMSCRIPTEN_EVENT_TOUCHCANCEL", + "EMSCRIPTEN_EVENT_GAMEPADCONNECTED", + "EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED", + "EMSCRIPTEN_EVENT_BEFOREUNLOAD", + "EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE", + "EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE", + "EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST", + "EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED", + + "EMSCRIPTEN_RESULT_SUCCESS", + "EMSCRIPTEN_RESULT_DEFERRED", + "EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED", + "EMSCRIPTEN_RESULT_INVALID_TARGET", + "EMSCRIPTEN_RESULT_INVALID_PARAM", + "EMSCRIPTEN_RESULT_NOT_SUPPORTED", + "EMSCRIPTEN_RESULT_FAILED", + "EMSCRIPTEN_RESULT_NO_DATA" + ], + "structs": { + "emscripten_KeyboardEvent": [ + "key", + "code", + "location", + "ctrlKey", + "shiftKey", + "altKey", + "metaKey", + "repeat", + "locale", + "charValue", + "charCode", + "keyCode", + "which" + ], + "emscripten_MouseEvent": [ + "timestamp", + "screenX", + "screenY", + "clientX", + "clientY", + "ctrlKey", + "shiftKey", + "altKey", + "metaKey", + "button", + "buttons", + "movementX", + "movementY", + "canvasX", + "canvasY" + ], + "emscripten_WheelEvent": [ + "mouse", + "deltaX", + "deltaY", + "deltaZ", + "deltaMode" + ], + "emscripten_UiEvent": [ + "detail", + "documentBodyClientWidth", + "documentBodyClientHeight", + "windowInnerWidth", + "windowInnerHeight", + "windowOuterWidth", + "windowOuterHeight", + "scrollTop", + "scrollLeft" + ], + "emscripten_FocusEvent": [ + "nodeName", + "id" + ], + "emscripten_DeviceOrientationEvent": [ + "timestamp", + "alpha", + "beta", + "gamma", + "absolute" + ], + "emscripten_DeviceMotionEvent": [ + "timestamp", + "accelerationX", + "accelerationY", + "accelerationZ", + "accelerationIncludingGravityX", + "accelerationIncludingGravityY", + "accelerationIncludingGravityZ", + "rotationRateAlpha", + "rotationRateBeta", + "rotationRateGamma" + ], + "emscripten_OrientationChangeEvent": [ + "orientationIndex", + "orientationAngle" + ], + "emscripten_FullscreenChangeEvent": [ + "isFullscreen", + "fullscreenEnabled", + "nodeName", + "id" + ], + "emscripten_PointerlockChangeEvent": [ + "isActive", + "nodeName", + "id" + ], + "emscripten_VisibilityChangeEvent": [ + "hidden", + "visibilityState" + ], + "emscripten_TouchPoint": [ + "identifier", + "screenX", + "screenY", + "clientX", + "clientY", + "pageX", + "pageY", + "isChanged", + "onTarget", + "canvasX", + "canvasY" + ], + "emscripten_TouchEvent": [ + "numTouches", + "ctrlKey", + "shiftKey", + "altKey", + "metaKey", + "touches" + ], + "emscripten_GamepadEvent": [ + "timestamp", + "axis", + "analogButton", + "digitalButton", + "connected", + "index", + "numAxes", + "numButtons", + "id", + "mapping" + ], + "emscripten_BatteryEvent": [ + "chargingTime", + "dischargingTime", + "level", + "charging" + ] + } } -] + ] diff --git a/system/include/emscripten/events.h b/system/include/emscripten/events.h new file mode 100644 index 000000000..4caae3cfd --- /dev/null +++ b/system/include/emscripten/events.h @@ -0,0 +1,625 @@ +#ifndef __emscripten_events_h__ +#define __emscripten_events_h__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* This file defines Emscripten low-level glue bindings for interfacing with the following HTML5 APIs: + * - DOM Level 3 Events: Keyboard, Mouse, Mouse Wheel, Resize, Scroll, Focus. See https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html + * - DeviceOrientation Events for gyro and accelerometer. See http://www.w3.org/TR/orientation-event/ + * - Screen Orientation Events for portrait/landscape handling. See https://dvcs.w3.org/hg/screen-orientation/raw-file/tip/Overview.html + * - Fullscreen Events for browser canvas fullscreen modes transitioning. See https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html + * - Pointer Lock Events for relative-mode mouse motion control. See http://www.w3.org/TR/pointerlock/ + * - Vibration API for mobile device haptic vibration feedback control. See http://dev.w3.org/2009/dap/vibration/ + * - Page Visibility Events for power management control. See http://www.w3c-test.org/webperf/specs/PageVisibility/ + * - Touch Events. See http://www.w3.org/TR/touch-events/ + * - Gamepad API. See http://www.w3.org/TR/gamepad/ + * - Beforeunload event. See http://www.whatwg.org/specs/web-apps/current-work/multipage/history.html#beforeunloadevent + * - WebGL context events. See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2 + * + * Most web APIs are event-based, which means that the functionality is accessed by registering a callback function to be called when the event occurs. The + * Gamepad API is currently an exception, for which only a polling API is available. For some APIs, both an event-based and a polling-based API is exposed. + * + * Calling a callback registration function with a null pointer function causes an unregistration of that callback from the given target element. All event + * handlers are also automatically unregistered when the C exit() function is invoked during the atexit handler pass. Use either the function + * emscripten_set_main_loop() or set Module.noExitRuntime = true; to make sure that leaving main() will not immediately cause an exit() and clean up the + * event handlers. + * + * Throughout this file, the function signatures have a 'target' parameter. This parameter allows specifying the HTML Element ID to which the callback + * registration is to be applied to. This field has the following special meanings: + * - 0 or NULL: A default element is chosen automatically based on the event type, which should be reasonable most of the time. + * - "#window": The event listener is applied to the JS 'window' object. + * - "#document": The event listener is applied to the JS 'document' object. + * - "#screen": The event listener is applied to the JS 'window.screen' object. + * - "#canvas": The event listener is applied to the Emscripten default WebGL canvas element. + * - Any other string without a leading hash "#" sign: The event listener is applied to the element by the given ID on the page. + * + * The callback hook functions also take in a 'userData' parameter. This is a custom user-defineable value that will be carried through unchanged to all + * invocations of the registered event callback. Use this e.g. to pass a pointer to a C++ class or similar to enclose the C API in a clean object-oriented manner. + * + * Callback handlers that return an EM_BOOL may return nonzero to signal that the default action for that event is to be suppressed. This will call + * the .preventDefault(); member on the event. Returning zero will cause the default browser event action to be carried out. + * + * Most functions return the result using the type EMSCRIPTEN_RESULT. Nonzero and positive values denote success. Negative values + * signal failure. None of the functions fail or abort by throwing a JS or C++ exception. If a particular browser does not support the given feature, + * the value EMSCRIPTEN_RESULT_NOT_SUPPORTED will be returned at the time the callback is registered. + * + * Due to web security purposes, the pointer lock and fullscreen requests can only be invoked from inside an user-originated event handler. Such requests + * are automatically deferred until the user presses a keyboard or mouse button the next time. + */ + +#define EMSCRIPTEN_EVENT_KEYPRESS 1 +#define EMSCRIPTEN_EVENT_KEYDOWN 2 +#define EMSCRIPTEN_EVENT_KEYUP 3 +#define EMSCRIPTEN_EVENT_CLICK 4 +#define EMSCRIPTEN_EVENT_MOUSEDOWN 5 +#define EMSCRIPTEN_EVENT_MOUSEUP 6 +#define EMSCRIPTEN_EVENT_DBLCLICK 7 +#define EMSCRIPTEN_EVENT_MOUSEMOVE 8 +#define EMSCRIPTEN_EVENT_WHEEL 9 +#define EMSCRIPTEN_EVENT_RESIZE 10 +#define EMSCRIPTEN_EVENT_SCROLL 11 +#define EMSCRIPTEN_EVENT_BLUR 12 +#define EMSCRIPTEN_EVENT_FOCUS 13 +#define EMSCRIPTEN_EVENT_FOCUSIN 14 +#define EMSCRIPTEN_EVENT_FOCUSOUT 15 +#define EMSCRIPTEN_EVENT_DEVICEORIENTATION 16 +#define EMSCRIPTEN_EVENT_DEVICEMOTION 17 +#define EMSCRIPTEN_EVENT_ORIENTATIONCHANGE 18 +#define EMSCRIPTEN_EVENT_FULLSCREENCHANGE 19 +#define EMSCRIPTEN_EVENT_POINTERLOCKCHANGE 20 +#define EMSCRIPTEN_EVENT_VISIBILITYCHANGE 21 +#define EMSCRIPTEN_EVENT_TOUCHSTART 22 +#define EMSCRIPTEN_EVENT_TOUCHEND 23 +#define EMSCRIPTEN_EVENT_TOUCHMOVE 24 +#define EMSCRIPTEN_EVENT_TOUCHCANCEL 25 +#define EMSCRIPTEN_EVENT_GAMEPADCONNECTED 26 +#define EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED 27 +#define EMSCRIPTEN_EVENT_BEFOREUNLOAD 28 +#define EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE 29 +#define EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE 30 +#define EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST 31 +#define EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED 32 + +#define EMSCRIPTEN_RESULT int + +// The operation succeeded +#define EMSCRIPTEN_RESULT_SUCCESS 0 + +// For web security reasons, the requested operation cannot be completed now, but was deferred for completion in the next event handler. +#define EMSCRIPTEN_RESULT_DEFERRED 1 + +// The given operation is not supported by this browser or the target element. +#define EMSCRIPTEN_RESULT_NOT_SUPPORTED -1 + +// For web security reasons, the requested operation could not be completed now, and it failed since the user requested the operation to not be deferred. +#define EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED -2 + +// The given target element for the operation is invalid. +#define EMSCRIPTEN_RESULT_INVALID_TARGET -3 + +// An invalid parameter was passed to the function. +#define EMSCRIPTEN_RESULT_INVALID_PARAM -4 + +// The operation failed due to some generic reason. +#define EMSCRIPTEN_RESULT_FAILED -5 + +// Operation failed since no data is currently available. +#define EMSCRIPTEN_RESULT_NO_DATA -6 + +#define EM_BOOL int +#define EM_UTF8 char + +#define DOM_KEY_LOCATION int +#define DOM_KEY_LOCATION_STANDARD 0x00 +#define DOM_KEY_LOCATION_LEFT 0x01 +#define DOM_KEY_LOCATION_RIGHT 0x02 +#define DOM_KEY_LOCATION_NUMPAD 0x03 + +/* + * The event structure passed in keyboard events keypress, keydown and keyup. + * https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#keys + */ +typedef struct emscripten_KeyboardEvent { + // The printed representation of the pressed key. + EM_UTF8 key[32]; + // A string that identifies the physical key being pressed. The value is not affected by the current keyboard + // layout or modifier state, so a particular key will always return the same value. + EM_UTF8 code[32]; + // Indicates the location of the key on the keyboard. One of the DOM_KEY_LOCATION_ values. + unsigned long location; + // Specifies which modifiers were active during the key event. + EM_BOOL ctrlKey; + EM_BOOL shiftKey; + EM_BOOL altKey; + EM_BOOL metaKey; + // Specifies if this keyboard event represents a repeated press. + EM_BOOL repeat; + // A locale string indicating the locale the keyboard is configured for. This may be the empty string if the + // browser or device doesn't know the keyboard's locale. + EM_UTF8 locale[32]; + // The following fields are values from previous versions of the DOM key events specifications. + // See https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent?redirectlocale=en-US&redirectslug=DOM%2FKeyboardEvent + // The character representation of the key. + EM_UTF8 charValue[32]; + // The Unicode reference number of the key; this attribute is used only by the keypress event. For keys whose char attribute + // contains multiple characters, this is the Unicode value of the first character in that attribute. + unsigned long charCode; + // A system and implementation dependent numerical code identifying the unmodified value of the pressed key. + unsigned long keyCode; + // A system and implementation dependent numeric code identifying the unmodified value of the pressed key; this is usually the same as keyCode. + unsigned long which; +} emscripten_KeyboardEvent; + +/* + * Registers a callback function for receiving browser-generated keyboard input events. + * See https://developer.mozilla.org/en/DOM/Event/UIEvent/KeyEvent + * and http://www.javascriptkit.com/jsref/eventkeyboardmouse.shtml + */ +extern EMSCRIPTEN_RESULT emscripten_set_keypress_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const emscripten_KeyboardEvent *keyEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_keydown_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const emscripten_KeyboardEvent *keyEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_keyup_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const emscripten_KeyboardEvent *keyEvent, void *userData)); + +/* + * The event structure passed in mouse events click, mousedown, mouseup, dblclick and mousemove. + * https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#interface-MouseEvent + */ +typedef struct emscripten_MouseEvent { + // A timestamp of when this data was generated by the browser. This is an absolute wallclock time in milliseconds. + double timestamp; + // The coordinate relative to the browser screen coordinate system. + long screenX; + long screenY; + // The coordinate relative to the viewport associate with the event. + long clientX; + long clientY; + // Specifies which modifiers were active during the mouse event. + EM_BOOL ctrlKey; + EM_BOOL shiftKey; + EM_BOOL altKey; + EM_BOOL metaKey; + // Which pointer device button changed state. + unsigned short button; + // A bitmask that indicates which combinations of mouse buttons were being held down at the time of the event. + unsigned short buttons; + // If pointer lock is active, these two extra fields give relative mouse movement since the last event. + long movementX; + long movementY; + // Emscripten-specific extension: These fields give the mouse coordinates mapped to the Emscripten canvas client area. + long canvasX; + long canvasY; + // Pad this struct to multiple of 8 bytes to make WheelEvent unambiguously align to 8 bytes. + long padding; +} emscripten_MouseEvent; + +/* + * Registers a callback function for receiving browser-generated mouse input events. + * See https://developer.mozilla.org/en/DOM/MouseEvent + */ +extern EMSCRIPTEN_RESULT emscripten_set_click_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const emscripten_MouseEvent *mouseEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_mousedown_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const emscripten_MouseEvent *mouseEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_mouseup_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const emscripten_MouseEvent *mouseEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_dblclick_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const emscripten_MouseEvent *mouseEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_mousemove_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const emscripten_MouseEvent *mouseEvent, void *userData)); +/* + * Returns the most recently received mouse event state. Note that for this function call to succeed, emscripten_set_xx_callback must have first + * been called with one of the mouse event types and a non-zero callback function pointer to enable the Mouse state capture. + */ +extern EMSCRIPTEN_RESULT emscripten_get_mouse_status(emscripten_MouseEvent *mouseState); + +#define DOM_DELTA_PIXEL 0x00 +#define DOM_DELTA_LINE 0x01 +#define DOM_DELTA_PAGE 0x02 + +/* + * The event structure passed in mouse wheelevent. + * https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#interface-WheelEvent + */ +typedef struct emscripten_WheelEvent { + // Specifies general mouse information related to this event. + emscripten_MouseEvent mouse; + // Measures along different axes the movement of the wheel. + double deltaX; + double deltaY; + double deltaZ; + // One of the DOM_DELTA_ values that indicates the units of measurement for the delta values. + unsigned long deltaMode; +} emscripten_WheelEvent; + +/* + * Registers a callback function for receiving browser-generated mouse wheel events. + * See http://www.w3.org/TR/DOM-Level-3-Events/#event-type-wheel + */ +extern EMSCRIPTEN_RESULT emscripten_set_wheel_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_WheelEvent *wheelEvent, void *userData)); + +/* + * The event structure passed in DOM element resize and scroll events. + * https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#interface-UIEvent + */ +typedef struct emscripten_UiEvent { + // Specifies detail information about this event. + long detail; + // The clientWidth/clientHeight of the document.body element. + int documentBodyClientWidth; + int documentBodyClientHeight; + // The innerWidth/innerHeight of the window element. + int windowInnerWidth; + int windowInnerHeight; + // The outerWidth/outerHeight of the window element. + int windowOuterWidth; + int windowOuterHeight; + // The page scroll position. + int scrollTop; + int scrollLeft; +} emscripten_UiEvent; + +/* + * Registers a callback function for receiving DOM element resize and scroll events. + * See https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#event-type-resize + */ +extern EMSCRIPTEN_RESULT emscripten_set_resize_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_UiEvent *uiEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_scroll_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_UiEvent *uiEvent, void *userData)); + +/* + * The event structure passed in DOM element blur, focus, focusin and focusout events. + * https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#interface-FocusEvent + */ +typedef struct emscripten_FocusEvent { + // The nodeName of the target HTML Element. See https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeName + EM_UTF8 nodeName[128]; + // The HTML Element ID of the target element. + EM_UTF8 id[128]; +} emscripten_FocusEvent; + +/* + * Registers a callback function for receiving DOM element blur, focus, focusin and focusout events. + * See https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#event-type-blur + */ +extern EMSCRIPTEN_RESULT emscripten_set_blur_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_FocusEvent *focusEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_focus_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_FocusEvent *focusEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_focusin_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_FocusEvent *focusEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_focusout_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_FocusEvent *focusEvent, void *userData)); + +/* + * The event structure passed in the deviceorientation event. + * http://dev.w3.org/geo/api/spec-source-orientation.html#deviceorientation + */ +typedef struct emscripten_DeviceOrientationEvent { + // Absolute wallclock time in msec units of when the event occurred. + double timestamp; + // The orientation of the device in terms of the transformation from a coordinate frame fixed on the Earth to a coordinate frame fixed in the device. + double alpha; + double beta; + double gamma; + // If false, the orientation is only relative to some other bas orinetation, not to the fixed coordinate frame. + EM_BOOL absolute; +} emscripten_DeviceOrientationEvent; + +/* + * Registers a callback function for receiving the deviceorientation event. + * See http://dev.w3.org/geo/api/spec-source-orientation.html + */ +extern EMSCRIPTEN_RESULT emscripten_set_deviceorientation_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_DeviceOrientationEvent *orientationEvent, void *userData)); +/* + * Returns the most recently received deviceorientation event state. Note that for this function call to succeed, emscripten_set_deviceorientation_callback + * must have first been called with one of the mouse event types and a non-zero callback function pointer to enable the Device Orientation state capture. + */ +extern EMSCRIPTEN_RESULT emscripten_get_deviceorientation_status(emscripten_DeviceOrientationEvent *orientationState); + +/* + * The event structure passed in the devicemotion event. + * http://dev.w3.org/geo/api/spec-source-orientation.html#devicemotion + */ +typedef struct emscripten_DeviceMotionEvent { + // Absolute wallclock time in msec units of when the event occurred. + double timestamp; + // Acceleration of the device excluding gravity. + double accelerationX; + double accelerationY; + double accelerationZ; + // Acceleration of the device including gravity. + double accelerationIncludingGravityX; + double accelerationIncludingGravityY; + double accelerationIncludingGravityZ; + // The rotational delta of the device. + double rotationRateAlpha; + double rotationRateBeta; + double rotationRateGamma; +} emscripten_DeviceMotionEvent; + +/* + * Registers a callback function for receiving the devicemotion event. + * See http://dev.w3.org/geo/api/spec-source-orientation.html + */ +extern EMSCRIPTEN_RESULT emscripten_set_devicemotion_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_DeviceMotionEvent *motionEvent, void *userData)); +/* + * Returns the most recently received deviceomotion event state. Note that for this function call to succeed, emscripten_set_devicemotion_callback + * must have first been called with one of the mouse event types and a non-zero callback function pointer to enable the Device Motion state capture. + */ +extern EMSCRIPTEN_RESULT emscripten_get_devicemotion_status(emscripten_DeviceMotionEvent *motionState); + +#define EMSCRIPTEN_ORIENTATION_PORTRAIT_PRIMARY 1 +#define EMSCRIPTEN_ORIENTATION_PORTRAIT_SECONDARY 2 +#define EMSCRIPTEN_ORIENTATION_LANDSCAPE_PRIMARY 4 +#define EMSCRIPTEN_ORIENTATION_LANDSCAPE_SECONDARY 8 + +/* + * The event structure passed in the orientationchange event. + * https://dvcs.w3.org/hg/screen-orientation/raw-file/tip/Overview.html + */ +typedef struct emscripten_OrientationChangeEvent { + // One of EM_ORIENTATION_PORTRAIT_xx fields, or -1 if unknown. + int orientationIndex; + // Emscripten-specific extension: Some browsers refer to 'window.orientation', so report that as well. + // Orientation angle in degrees. 0: "default orientation", i.e. default upright orientation to hold the mobile device in. Could be either landscape or portrait. + int orientationAngle; +} emscripten_OrientationChangeEvent; + +/* + * Registers a callback function for receiving the orientationchange event. + * https://dvcs.w3.org/hg/screen-orientation/raw-file/tip/Overview.html + */ +extern EMSCRIPTEN_RESULT emscripten_set_orientationchange_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_OrientationChangeEvent *orientationChangeEvent, void *userData)); +/* + * Returns the current device orientation state. + */ +extern EMSCRIPTEN_RESULT emscripten_get_orientation_status(emscripten_OrientationChangeEvent *orientationStatus); +/* + * Locks the screen orientation to the given set of allowed orientations. + * allowedOrientations: A bitfield set of EM_ORIENTATION_xx flags. + */ +extern EMSCRIPTEN_RESULT emscripten_lock_orientation(int allowedOrientations); +/* + * Allows the screen to turn again into any orientation. + */ +extern EMSCRIPTEN_RESULT emscripten_unlock_orientation(); + +/* + * The event structure passed in the fullscreenchange event. + * https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html + */ +typedef struct emscripten_FullscreenChangeEvent { + // Specifies whether an element on the browser page is currently fullscreen. + EM_BOOL isFullscreen; + // Specifies if the current page has the ability to display elements fullscreen. + EM_BOOL fullscreenEnabled; + // The nodeName of the target HTML Element that is in full screen mode. See https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeName + EM_UTF8 nodeName[128]; + // The HTML Element ID of the target HTML element that is in full screen mode. + EM_UTF8 id[128]; +} emscripten_FullscreenChangeEvent; + +/* + * Registers a callback function for receiving the fullscreenchange event. + * https://dvcs.w3.org/hg/screen-orientation/raw-file/tip/Overview.html + */ +extern EMSCRIPTEN_RESULT emscripten_set_fullscreenchange_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_FullscreenChangeEvent *fullscreenChangeEvent, void *userData)); +/* + * Returns the current page fullscreen state. + */ +extern EMSCRIPTEN_RESULT emscripten_get_fullscreen_status(emscripten_FullscreenChangeEvent *fullscreenStatus); +/* + * Requests the given target element to transition to full screen mode. + * Note: This function can only run inside a user-generated JavaScript event handler. + * deferUntilInEventHandler: If true and you called this function outside an event callback, this request will + * be queued to be executed the next time a JS event handler runs. If false, this + * function will instead fail if not running inside a JS event handler. + */ +extern EMSCRIPTEN_RESULT emscripten_request_fullscreen(const char *target, int deferUntilInEventHandler); +/* + * Returns back to windowed browsing mode. + */ +extern EMSCRIPTEN_RESULT emscripten_exit_fullscreen(); + +/* + * The event structure passed in the pointerlockchange event. + * http://www.w3.org/TR/pointerlock/ + */ +typedef struct emscripten_PointerlockChangeEvent { + // Specifies whether an element on the browser page currently has pointer lock enabled. + EM_BOOL isActive; + // The nodeName of the target HTML Element that has the pointer lock active. See https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeName + EM_UTF8 nodeName[128]; + // The HTML Element ID of the target HTML element that has the pointer lock active. + EM_UTF8 id[128]; +} emscripten_PointerlockChangeEvent; + +/* + * Registers a callback function for receiving the pointerlockchange event. + * Pointer lock hides the mouse cursor and exclusively gives the target element relative mouse movement events via the mousemove event. + * http://www.w3.org/TR/pointerlock/ + */ +extern EMSCRIPTEN_RESULT emscripten_set_pointerlockchange_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_PointerlockChangeEvent *pointerlockChangeEvent, void *userData)); +/* + * Returns the current page pointerlock state. + */ +extern EMSCRIPTEN_RESULT emscripten_get_pointerlock_status(emscripten_PointerlockChangeEvent *pointerlockStatus); +/* + * Requests the given target element to grab pointerlock. + * Note: This function can only run inside a user-generated JavaScript event handler. + * deferUntilInEventHandler: If true and you called this function outside an event callback, this request will + * be queued to be executed the next time a JS event handler runs. If false, this + * function will instead fail if not running inside a JS event handler. + */ +extern EMSCRIPTEN_RESULT emscripten_request_pointerlock(const char *target, int deferUntilInEventHandler); +/* + * Exits pointer lock state and restores the mouse cursor to be visible again. + */ +extern EMSCRIPTEN_RESULT emscripten_exit_pointerlock(); + +#define EMSCRIPTEN_VISIBILITY_HIDDEN 0 +#define EMSCRIPTEN_VISIBILITY_VISIBLE 1 +#define EMSCRIPTEN_VISIBILITY_PRERENDER 2 +#define EMSCRIPTEN_VISIBILITY_UNLOADED 3 + +/* + * The event structure passed in the visibilitychange event. + * http://www.w3c-test.org/webperf/specs/PageVisibility/ + */ +typedef struct emscripten_VisibilityChangeEvent { + // If true, the current browser page is now hidden. + EM_BOOL hidden; + // Specifies a more fine-grained state of the current page visibility status. One of the EMSCRIPTEN_VISIBILITY_ values. + int visibilityState; +} emscripten_VisibilityChangeEvent; + +/* + * Registers a callback function for receiving the visibilitychange event. + * http://www.w3c-test.org/webperf/specs/PageVisibility/ + */ +extern EMSCRIPTEN_RESULT emscripten_set_visibilitychange_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_VisibilityChangeEvent *visibilityChangeEvent, void *userData)); +/* + * Returns the current page visibility state. + */ +extern EMSCRIPTEN_RESULT emscripten_get_visibility_status(emscripten_VisibilityChangeEvent *visibilityStatus); + +/* + * Specifies the status of a single touch point on the page. + * See http://www.w3.org/TR/touch-events/#touch-interface + */ +typedef struct emscripten_TouchPoint +{ + // An identification number for each touch point. + long identifier; + // The touch coordinate relative to the whole screen origin, in pixels. + long screenX; + long screenY; + // The touch coordinate relative to the viewport, in pixels. + long clientX; + long clientY; + // The touch coordinate relative to the viewport, in pixels, and including any scroll offset. + long pageX; + long pageY; + // Specifies whether this touch point changed during this event. + EM_BOOL isChanged; + // Specifies whether this touch point is still above the original target on which it was initially pressed against. + EM_BOOL onTarget; + // The touch coordinates mapped to the Emscripten canvas client area, in pixels. + long canvasX; + long canvasY; +} emscripten_TouchPoint; + +/* + * Specifies the data of a single touch event. + * See http://www.w3.org/TR/touch-events/#touchevent-interface + */ +typedef struct emscripten_TouchEvent { + // The number of valid elements in the touches array. + int numTouches; + // Specifies which modifiers were active during the key event. + EM_BOOL ctrlKey; + EM_BOOL shiftKey; + EM_BOOL altKey; + EM_BOOL metaKey; + // An array of currently active touches, one for each finger. + emscripten_TouchPoint touches[32]; +} emscripten_TouchEvent; + +/* + * Registers a callback function for receiving the touchstart, touchend, touchmove and touchcancel events. + * http://www.w3.org/TR/touch-events/ + */ +extern EMSCRIPTEN_RESULT emscripten_set_touchstart_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_TouchEvent *touchEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_touchend_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_TouchEvent *touchEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_touchmove_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_TouchEvent *touchEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_touchcancel_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_TouchEvent *touchEvent, void *userData)); + +/* + * Represents the current snapshot state of a gamepad. + * http://www.w3.org/TR/gamepad/#gamepad-interface + */ +typedef struct emscripten_GamepadEvent { + // Absolute wallclock time in msec units of when the data was recorded. + double timestamp; + // The number of valid axes entries in the axis array. + int numAxes; + // The number of valid button entries in the analogButton and digitalButton arrays. + int numButtons; + // The analog state of the gamepad axes, in the range [-1, 1]. + double axis[64]; + // The analog state of the gamepad buttons, in the range [0, 1]. + double analogButton[64]; + // The digital state of the gamepad buttons, either 0 or 1. + EM_BOOL digitalButton[64]; + // Specifies whether this gamepad is connected to the browser page. + EM_BOOL connected; + // An ordinal associated with this gamepad, zero-based. + long index; + // An ID for the brand or style of the connected gamepad device. Typically, this will include the USB vendor and a product ID. + EM_UTF8 id[64]; + // A string that identifies the layout or control mapping of this device. + EM_UTF8 mapping[64]; +} emscripten_GamepadEvent; + +/* + * Registers a callback function for receiving the gamepadconnected and gamepaddisconnected events. + * http://www.w3.org/TR/gamepad/ + */ +extern EMSCRIPTEN_RESULT emscripten_set_gamepadconnected_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_GamepadEvent *gamepadEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_gamepaddisconnected_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_GamepadEvent *gamepadEvent, void *userData)); + +/* + * Returns the number of gamepads connected to the system or EMSCRIPTEN_RESULT_NOT_SUPPORTED if the current browser does not support gamepads. + * Note: A gamepad does not show up as connected until a button on it is pressed. + */ +extern int emscripten_get_num_gamepads(); +/* + * Returns a snapshot of the current gamepad state. + */ +extern EMSCRIPTEN_RESULT emscripten_get_gamepad_status(int index, emscripten_GamepadEvent *gamepadState); + +/* + * The event structure passed in the battery chargingchange and levelchange event. + * http://www.w3.org/TR/battery-status/#batterymanager-interface + */ +typedef struct emscripten_BatteryEvent { + double chargingTime; + double dischargingTime; + double level; + EM_BOOL charging; +} emscripten_BatteryEvent; + +/* + * Registers a callback function for receiving the battery chargingchange and levelchange events. + * http://www.w3.org/TR/battery-status/ + */ +extern EMSCRIPTEN_RESULT emscripten_set_batterychargingchange_callback(void *userData, EM_BOOL (*func)(int eventType, const emscripten_BatteryEvent *batteryEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_batterylevelchange_callback(void *userData, EM_BOOL (*func)(int eventType, const emscripten_BatteryEvent *batteryEvent, void *userData)); +/* + * Returns the current battery status. + */ +extern EMSCRIPTEN_RESULT emscripten_get_battery_status(emscripten_BatteryEvent *batteryState); + +/* + * Produces a vibration feedback for given msecs. + * http://dev.w3.org/2009/dap/vibration/ + */ +extern EMSCRIPTEN_RESULT emscripten_vibrate(int msecs); +/* + * Produces a complex vibration feedback pattern. + * msecsArray: An array of timing entries [on, off, on, off, on, off, ...] where every second one specifies a duration of vibration, and + * every other one specifies a duration of silence. + * numEntries: The number of integers in the array msecsArray. + */ +extern EMSCRIPTEN_RESULT emscripten_vibrate_pattern(int *msecsArray, int numEntries); + +/* + * Registers a callback function for receiving the page beforeunload event. + * Hook onto this event to perform process right prior to page close, and/or display a confirmation notification asking if the user really wants to leave the page. + * http://www.whatwg.org/specs/web-apps/current-work/multipage/history.html#beforeunloadevent + */ +extern EMSCRIPTEN_RESULT emscripten_set_beforeunload_callback(void *userData, const char *(*func)(int eventType, const void *reserved, void *userData)); + +/* + * Registers a callback function for the canvas webgl context webglcontextlost and webglcontextrestored events. + * See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2 + */ +extern EMSCRIPTEN_RESULT emscripten_set_webglcontextlost_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const void *reserved, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_webglcontextrestored_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const void *reserved, void *userData)); + +#ifdef __cplusplus +} // ~extern "C" +#endif + +#endif diff --git a/tests/test_browser.py b/tests/test_browser.py index 9321f5293..e7139f6ef 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -1768,3 +1768,5 @@ Module["preRun"].push(function () { self.btest('doublestart.c', args=['--pre-js', 'pre.js', '-o', 'test.html'], expected='1') + def test_events(self): + self.btest(path_from_root('tests', 'test_events.c'), expected='0') diff --git a/tests/test_events.c b/tests/test_events.c new file mode 100644 index 000000000..23fa87045 --- /dev/null +++ b/tests/test_events.c @@ -0,0 +1,382 @@ +#include +#include +#include +#include + +static inline const char *emscripten_event_type_to_string(int eventType) { + const char *events[] = { "(invalid)", "(none)", "keypress", "keydown", "keyup", "click", "mousedown", "mouseup", "dblclick", "mousemove", "wheel", "resize", + "scroll", "blur", "focus", "focusin", "focusout", "deviceorientation", "devicemotion", "orientationchange", "fullscreenchange", "pointerlockchange", + "visibilitychange", "touchstart", "touchend", "touchmove", "touchcancel", "gamepadconnected", "gamepaddisconnected", "beforeunload", + "batterychargingchange", "batterylevelchange", "webglcontextlost", "webglcontextrestored", "(invalid)" }; + ++eventType; + if (eventType < 0) eventType = 0; + if (eventType >= sizeof(events)/sizeof(events[0])) eventType = sizeof(events)/sizeof(events[0])-1; + return events[eventType]; +} + +// The event handler functions can return 1 to suppress the event and disable the default action. That calls event.preventDefault(); +// Returning 0 signals that the event was not consumed by the code, and will allow the event to pass on and bubble up normally. +EM_BOOL key_callback(int eventType, const emscripten_KeyboardEvent *e, void *userData) +{ + printf("%s, key: \"%s\", code: \"%s\", location: %lu,%s%s%s%s repeat: %d, locale: \"%s\", char: \"%s\", charCode: %lu, keyCode: %lu, which: %lu\n", + emscripten_event_type_to_string(eventType), e->key, e->code, e->location, + e->ctrlKey ? " CTRL" : "", e->shiftKey ? " SHIFT" : "", e->altKey ? " ALT" : "", e->metaKey ? " META" : "", + e->repeat, e->locale, e->charValue, e->charCode, e->keyCode, e->which); + + if (eventType == EMSCRIPTEN_EVENT_KEYPRESS && !strcmp(e->key, "f")) { + emscripten_FullscreenChangeEvent fsce; + emscripten_get_fullscreen_status(&fsce); + if (!fsce.isFullscreen) { + emscripten_request_fullscreen(0, 1); + } else { + emscripten_exit_fullscreen(); + } + } + + if (eventType == EMSCRIPTEN_EVENT_KEYPRESS && !strcmp(e->key, "p")) { + emscripten_PointerlockChangeEvent plce; + emscripten_get_pointerlock_status(&plce); + if (!plce.isActive) { + emscripten_request_pointerlock(0, 1); + } else { + emscripten_exit_pointerlock(); + } + } + + return 0; +} + +EM_BOOL mouse_callback(int eventType, const emscripten_MouseEvent *e, void *userData) +{ + printf("%s, screen: (%ld,%ld), client: (%ld,%ld),%s%s%s%s button: %hu, buttons: %hu, movement: (%ld,%ld), canvas: (%ld,%ld)\n", + emscripten_event_type_to_string(eventType), e->screenX, e->screenY, e->clientX, e->clientY, + e->ctrlKey ? " CTRL" : "", e->shiftKey ? " SHIFT" : "", e->altKey ? " ALT" : "", e->metaKey ? " META" : "", + e->button, e->buttons, e->movementX, e->movementY, e->canvasX, e->canvasY); + + return 0; +} + +EM_BOOL wheel_callback(int eventType, const emscripten_WheelEvent *e, void *userData) +{ + printf("%s, screen: (%ld,%ld), client: (%ld,%ld),%s%s%s%s button: %hu, buttons: %hu, canvas: (%ld,%ld), delta:(%g,%g,%g), deltaMode:%lu\n", + emscripten_event_type_to_string(eventType), e->mouse.screenX, e->mouse.screenY, e->mouse.clientX, e->mouse.clientY, + e->mouse.ctrlKey ? " CTRL" : "", e->mouse.shiftKey ? " SHIFT" : "", e->mouse.altKey ? " ALT" : "", e->mouse.metaKey ? " META" : "", + e->mouse.button, e->mouse.buttons, e->mouse.canvasX, e->mouse.canvasY, + (float)e->deltaX, (float)e->deltaY, (float)e->deltaZ, e->deltaMode); + + return 0; +} + +EM_BOOL uievent_callback(int eventType, const emscripten_UiEvent *e, void *userData) +{ + printf("%s, detail: %ld, document.body.client size: (%d,%d), window.inner size: (%d,%d), scrollPos: (%d, %d)\n", + emscripten_event_type_to_string(eventType), e->detail, e->documentBodyClientWidth, e->documentBodyClientHeight, + e->windowInnerWidth, e->windowInnerHeight, e->scrollTop, e->scrollLeft); + + return 0; +} + +EM_BOOL focusevent_callback(int eventType, const emscripten_FocusEvent *e, void *userData) +{ + printf("%s, nodeName: \"%s\", id: \"%s\"\n", emscripten_event_type_to_string(eventType), e->nodeName, e->id[0] == '\0' ? "(empty string)" : e->id); + + return 0; +} + +EM_BOOL deviceorientation_callback(int eventType, const emscripten_DeviceOrientationEvent *e, void *userData) +{ + printf("%s, (%g, %g, %g)\n", emscripten_event_type_to_string(eventType), e->alpha, e->beta, e->gamma); + + return 0; +} + +EM_BOOL devicemotion_callback(int eventType, const emscripten_DeviceMotionEvent *e, void *userData) +{ + printf("%s, accel: (%g, %g, %g), accelInclGravity: (%g, %g, %g), rotationRate: (%g, %g, %g)\n", + emscripten_event_type_to_string(eventType), + e->accelerationX, e->accelerationY, e->accelerationZ, + e->accelerationIncludingGravityX, e->accelerationIncludingGravityY, e->accelerationIncludingGravityZ, + e->rotationRateAlpha, e->rotationRateBeta, e->rotationRateGamma); + + return 0; +} + +EM_BOOL orientationchange_callback(int eventType, const emscripten_OrientationChangeEvent *e, void *userData) +{ + printf("%s, orientationAngle: %d, orientationIndex: %d\n", emscripten_event_type_to_string(eventType), e->orientationAngle, e->orientationIndex); + + return 0; +} + +EM_BOOL fullscreenchange_callback(int eventType, const emscripten_FullscreenChangeEvent *e, void *userData) +{ + printf("%s, isFullscreen: %d, fullscreenEnabled: %d, fs element nodeName: \"%s\", fs element id: \"%s\"\n", + emscripten_event_type_to_string(eventType), e->isFullscreen, e->fullscreenEnabled, e->nodeName, e->id); + + return 0; +} + +EM_BOOL pointerlockchange_callback(int eventType, const emscripten_PointerlockChangeEvent *e, void *userData) +{ + printf("%s, isActive: %d, pointerlock element nodeName: \"%s\", id: \"%s\"\n", + emscripten_event_type_to_string(eventType), e->isActive, e->nodeName, e->id); + + return 0; +} + +EM_BOOL visibilitychange_callback(int eventType, const emscripten_VisibilityChangeEvent *e, void *userData) +{ + printf("%s, hidden: %d, visibilityState: %d\n", emscripten_event_type_to_string(eventType), e->hidden, e->visibilityState); + + return 0; +} + +EM_BOOL touch_callback(int eventType, const emscripten_TouchEvent *e, void *userData) +{ + printf("%s, numTouches: %d %s%s%s%s\n", + emscripten_event_type_to_string(eventType), e->numTouches, + e->ctrlKey ? " CTRL" : "", e->shiftKey ? " SHIFT" : "", e->altKey ? " ALT" : "", e->metaKey ? " META" : ""); + for(int i = 0; i < e->numTouches; ++i) + { + const emscripten_TouchPoint *t = &e->touches[i]; + printf(" %ld: screen: (%ld,%ld), client: (%ld,%ld), page: (%ld,%ld), isChanged: %d, onTarget: %d, canvas: (%ld, %ld)\n", + t->identifier, t->screenX, t->screenY, t->clientX, t->clientY, t->pageX, t->pageY, t->isChanged, t->onTarget, t->canvasX, t->canvasY); + } + + return 0; +} + +EM_BOOL gamepad_callback(int eventType, const emscripten_GamepadEvent *e, void *userData) +{ + printf("%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"\n", + eventType != 0 ? emscripten_event_type_to_string(eventType) : "Gamepad state", e->timestamp, e->connected, e->index, + e->numAxes, e->numButtons, e->id, e->mapping); + + if (e->connected) + { + for(int i = 0; i < e->numAxes; ++i) + printf("Axis %d: %g\n", i, e->axis[i]); + + for(int i = 0; i < e->numButtons; ++i) + printf("Button %d: Digital: %d, Analog: %g\n", i, e->digitalButton[i], e->analogButton[i]); + } + + return 0; +} + +const char *beforeunload_callback(int eventType, const void *reserved, void *userData) +{ +#ifdef REPORT_RESULT + return ""; // For test harness, don't show a confirmation dialog to not block and keep the test runner automated. +#else + return "Do you really want to leave the page?"; +#endif +} + +void formatTime(char *str, int seconds) +{ + int h = seconds / (60*60); + seconds -= h*60*60; + int m = seconds / 60; + seconds -= m*60; + if (h > 0) + { + sprintf(str, "%dh:%02dm:%02ds", h, m, seconds); + } + else + { + sprintf(str, "%02dm:%02ds", m, seconds); + } +} + +EM_BOOL battery_callback(int eventType, const emscripten_BatteryEvent *e, void *userData) +{ + char t1[64]; + formatTime(t1, (int)e->chargingTime); + char t2[64]; + formatTime(t2, (int)e->dischargingTime); + printf("%s: chargingTime: %s, dischargingTime: %s, level: %g%%, charging: %d\n", + emscripten_event_type_to_string(eventType), t1, t2, e->level*100, e->charging); + + return 0; +} + +EM_BOOL webglcontext_callback(int eventType, const void *reserved, void *userData) +{ + printf("%s.\n", emscripten_event_type_to_string(eventType)); + + return 0; +} + +emscripten_GamepadEvent prevState[32]; +int prevNumGamepads = 0; + +void mainloop() +{ + int numGamepads = emscripten_get_num_gamepads(); + if (numGamepads != prevNumGamepads) + { + printf("Number of connected gamepads: %d\n", numGamepads); + prevNumGamepads = numGamepads; + } + + for(int i = 0; i < numGamepads && i < 32; ++i) + { + emscripten_GamepadEvent ge; + int failed = emscripten_get_gamepad_status(i, &ge); + if (!failed) + { + int g = ge.index; + for(int j = 0; j < ge.numAxes; ++j) + { + if (ge.axis[j] != prevState[g].axis[j]) + printf("Gamepad %d, axis %d: %g\n", g, j, ge.axis[j]); + } + + for(int j = 0; j < ge.numButtons; ++j) + { + if (ge.analogButton[j] != prevState[g].analogButton[j] || ge.digitalButton[j] != prevState[g].digitalButton[j]) + printf("Gamepad %d, button %d: Digital: %d, Analog: %g\n", g, j, ge.digitalButton[j], ge.analogButton[j]); + } + prevState[g] = ge; + } + } + +} + +#ifdef REPORT_RESULT +void report_result(void *arg) +{ + int result = 0; + REPORT_RESULT(); +} +#endif + +int main() +{ + emscripten_set_keypress_callback(0, 0, 1, key_callback); + emscripten_set_keydown_callback(0, 0, 1, key_callback); + emscripten_set_keyup_callback(0, 0, 1, key_callback); + + emscripten_set_click_callback(0, 0, 1, mouse_callback); + emscripten_set_mousedown_callback(0, 0, 1, mouse_callback); + emscripten_set_mouseup_callback(0, 0, 1, mouse_callback); + emscripten_set_dblclick_callback(0, 0, 1, mouse_callback); + emscripten_set_mousemove_callback(0, 0, 1, mouse_callback); + + emscripten_set_wheel_callback(0, 0, 1, wheel_callback); + + emscripten_set_resize_callback(0, 0, 1, uievent_callback); + emscripten_set_scroll_callback(0, 0, 1, uievent_callback); + + emscripten_set_blur_callback(0, 0, 1, focusevent_callback); + emscripten_set_focus_callback(0, 0, 1, focusevent_callback); + emscripten_set_focusin_callback(0, 0, 1, focusevent_callback); + emscripten_set_focusout_callback(0, 0, 1, focusevent_callback); + + emscripten_set_deviceorientation_callback(0, 1, deviceorientation_callback); + emscripten_set_devicemotion_callback(0, 1, devicemotion_callback); + + emscripten_set_orientationchange_callback(0, 1, orientationchange_callback); + + // Test the polling of orientation. + emscripten_OrientationChangeEvent oce; + emscripten_get_orientation_status(&oce); + printf("The current orientation is:\n"); + orientationchange_callback(EMSCRIPTEN_EVENT_ORIENTATIONCHANGE, &oce, 0); + + int newOrientation = (oce.orientationIndex == EMSCRIPTEN_ORIENTATION_PORTRAIT_PRIMARY + || oce.orientationIndex == EMSCRIPTEN_ORIENTATION_PORTRAIT_SECONDARY) ? EMSCRIPTEN_ORIENTATION_LANDSCAPE_PRIMARY : EMSCRIPTEN_ORIENTATION_PORTRAIT_PRIMARY; + printf("Locking orientation to state %d..\n", newOrientation); + // Test locking of orientation. + int failed = emscripten_lock_orientation(newOrientation); + + if (failed) + printf("No support for orientation lock!\n"); + + emscripten_get_orientation_status(&oce); + printf("The current orientation is after locking:\n"); + orientationchange_callback(18, &oce, 0); + + printf("Unlocking orientation..\n"); + emscripten_unlock_orientation(); + + emscripten_FullscreenChangeEvent fsce; + emscripten_get_fullscreen_status(&fsce); + printf("The current fullscreen status is:\n"); + fullscreenchange_callback(EMSCRIPTEN_EVENT_FULLSCREENCHANGE, &fsce, 0); + + emscripten_set_fullscreenchange_callback(0, 1, fullscreenchange_callback); + + // These won't do anything, since fullscreen must be requested in an event handler, + // but call these anyways to confirm that they don't crash in an exception in the test suite. + failed = emscripten_request_fullscreen(0, 1); + if (failed != 0 && failed != 3) + printf("Fullscreen request failed! (%d)\n", failed); + emscripten_exit_fullscreen(); + + emscripten_PointerlockChangeEvent plce; + emscripten_get_pointerlock_status(&plce); + printf("The current pointerlock status is:\n"); + pointerlockchange_callback(EMSCRIPTEN_EVENT_POINTERLOCKCHANGE, &plce, 0); + + emscripten_set_pointerlockchange_callback(0, 1, pointerlockchange_callback); + + // These won't do anything, since pointer lock must be requested in an event handler, + // but call these anyways to confirm that they don't crash in an exception in the test suite. + failed = emscripten_request_pointerlock(0, 1); + if (failed != 0 && failed != 3) + printf("Pointer lock request failed! (%d)\n", failed); + emscripten_exit_pointerlock(); + + int vibratePattern[] = { + 150, 500, + 300, 500, + 450 + }; + emscripten_vibrate_pattern(vibratePattern, sizeof(vibratePattern)/sizeof(vibratePattern[0])); + + emscripten_VisibilityChangeEvent vce; + emscripten_get_visibility_status(&vce); + printf("Current visibility status:\n"); + visibilitychange_callback(EMSCRIPTEN_EVENT_VISIBILITYCHANGE, &vce, 0); + + emscripten_set_visibilitychange_callback(0, 1, visibilitychange_callback); + + emscripten_set_touchstart_callback(0, 0, 1, touch_callback); + emscripten_set_touchend_callback(0, 0, 1, touch_callback); + emscripten_set_touchmove_callback(0, 0, 1, touch_callback); + emscripten_set_touchcancel_callback(0, 0, 1, touch_callback); + + emscripten_set_gamepadconnected_callback(0, 1, gamepad_callback); + emscripten_set_gamepaddisconnected_callback(0, 1, gamepad_callback); + + emscripten_set_main_loop(mainloop, 10, 0); + + emscripten_set_beforeunload_callback(0, beforeunload_callback); + + emscripten_set_batterychargingchange_callback(0, battery_callback); + emscripten_set_batterylevelchange_callback(0, battery_callback); + + emscripten_BatteryEvent bs; + failed = emscripten_get_battery_status(&bs); + if (failed) { + printf("Browser can not provide Battery Status information!\n"); + } else { + printf("Current battery status:\n"); + battery_callback(EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE, &bs, 0); + } + + emscripten_set_webglcontextlost_callback(0, 0, 1, webglcontext_callback); + emscripten_set_webglcontextrestored_callback(0, 0, 1, webglcontext_callback); + + /* For the events to function, one must either call emscripten_set_main_loop or enable Module.noExitRuntime by some other means. + Otherwise the application will exit after leaving main(), and the atexit handlers will clean up all event hooks (by design). */ + EM_ASM(Module['noExitRuntime'] = true); + +#ifdef REPORT_RESULT + // Keep the page running for a moment. + emscripten_async_call(report_result, 0, 5000); +#endif + return 0; +} From d655dd640096c0de8df62eac6259766773e378d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 22 Jan 2014 19:02:10 +0200 Subject: [PATCH 2/3] Bump version after adding new entries to src/struct_info.json. --- tools/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/shared.py b/tools/shared.py index e28a66c3d..665a6d526 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -345,7 +345,7 @@ def find_temp_directory(): # we re-check sanity when the settings are changed) # We also re-check sanity and clear the cache when the version changes -EMSCRIPTEN_VERSION = '1.9.3' +EMSCRIPTEN_VERSION = '1.9.4' def generate_sanity(): return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT + '|' + get_clang_version() From 9f7690fa3de0d28ed93c88f2a80537a79bfd2847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 24 Jan 2014 11:57:18 +0200 Subject: [PATCH 3/3] Rename library_events to library_html5 and other suggested renamings. Add better support for reporting EMSCRIPTEN_RESULT_NOT_SUPPORTED for unsupported features. --- src/{library_events.js => library_html5.js} | 720 +++++++++--------- src/modules.js | 2 +- src/struct_info.json | 35 +- .../include/emscripten/{events.h => html5.h} | 149 ++-- tests/test_browser.py | 4 +- tests/test_events.c | 382 ---------- tests/test_html5.c | 474 ++++++++++++ 7 files changed, 939 insertions(+), 827 deletions(-) rename src/{library_events.js => library_html5.js} (54%) rename system/include/emscripten/{events.h => html5.h} (86%) delete mode 100644 tests/test_events.c create mode 100644 tests/test_html5.c diff --git a/src/library_events.js b/src/library_html5.js similarity index 54% rename from src/library_events.js rename to src/library_html5.js index d1a861277..703f9a744 100644 --- a/src/library_events.js +++ b/src/library_html5.js @@ -1,5 +1,5 @@ -var LibraryJsEvents = { - $JsEvents: { +var LibraryJSEvents = { + $JSEvents: { // pointers to structs malloc()ed to Emscripten HEAP for JS->C interop. keyEvent: 0, mouseEvent: 0, @@ -18,13 +18,13 @@ var LibraryJsEvents = { removeEventListenersRegistered: false, registerRemoveEventListeners: function() { - if (!JsEvents.removeEventListenersRegistered) { + if (!JSEvents.removeEventListenersRegistered) { __ATEXIT__.push({ func: function() { - for(var i = JsEvents.eventHandlers.length-1; i >= 0; --i) { - JsEvents._removeHandler(i); + for(var i = JSEvents.eventHandlers.length-1; i >= 0; --i) { + JSEvents._removeHandler(i); } } }); - JsEvents.removeEventListenersRegistered = true; + JSEvents.removeEventListenersRegistered = true; } }, @@ -33,20 +33,13 @@ var LibraryJsEvents = { if (typeof target == "number") { target = Pointer_stringify(target); } - if (target == '#window') { - return window; - } else if (target == '#document') { - return document; - } else if (target == '#screen') { - return window.screen; - } else if (target == '#canvas') { - return Module['canvas']; - } - if (typeof target == 'string') { - return document.getElementById(target); - } else { - return target; - } + if (target == '#window') return window; + else if (target == '#document') return document; + else if (target == '#screen') return window.screen; + else if (target == '#canvas') return Module['canvas']; + + if (typeof target == 'string') return document.getElementById(target); + else return target; } else { // The sensible target varies between events, but use window as the default // since DOM events mostly can default to that. Specific callback registrations @@ -64,53 +57,50 @@ var LibraryJsEvents = { // and sort by that to always request fullscreen before pointer lock. deferCall: function(targetFunction, precedence, argsList) { function arraysHaveEqualContent(arrA, arrB) { - if (arrA.length != arrB.length) { - return false; - } + if (arrA.length != arrB.length) return false; + for(var i in arrA) { - if (arrA[i] != arrB[i]) { - return false; - } + if (arrA[i] != arrB[i]) return false; } return true; } // Test if the given call was already queued, and if so, don't add it again. - for(var i in JsEvents.deferredCalls) { - var call = JsEvents.deferredCalls[i]; + for(var i in JSEvents.deferredCalls) { + var call = JSEvents.deferredCalls[i]; if (call.targetFunction == targetFunction && arraysHaveEqualContent(call.argsList, argsList)) { return; } } - JsEvents.deferredCalls.push({ + JSEvents.deferredCalls.push({ targetFunction: targetFunction, precedence: precedence, argsList: argsList }); - JsEvents.deferredCalls.sort(function(x,y) { return x.precedence < y.precedence; }); + JSEvents.deferredCalls.sort(function(x,y) { return x.precedence < y.precedence; }); }, // Erases all deferred calls to the given target function from the queue list. removeDeferredCalls: function(targetFunction) { - for(var i = 0; i < JsEvents.deferredCalls.length; ++i) { - if (JsEvents.deferredCalls[i].targetFunction == targetFunction) { - JsEvents.deferredCalls.splice(i, 1); + for(var i = 0; i < JSEvents.deferredCalls.length; ++i) { + if (JSEvents.deferredCalls[i].targetFunction == targetFunction) { + JSEvents.deferredCalls.splice(i, 1); --i; } } }, canPerformEventHandlerRequests: function() { - return JsEvents.inEventHandler && JsEvents.currentEventHandler.allowsDeferredCalls; + return JSEvents.inEventHandler && JSEvents.currentEventHandler.allowsDeferredCalls; }, runDeferredCalls: function() { - if (!JsEvents.canPerformEventHandlerRequests()) { + if (!JSEvents.canPerformEventHandlerRequests()) { return; } - for(var i = 0; i < JsEvents.deferredCalls.length; ++i) { - var call = JsEvents.deferredCalls[i]; - JsEvents.deferredCalls.splice(i, 1); + for(var i = 0; i < JSEvents.deferredCalls.length; ++i) { + var call = JSEvents.deferredCalls[i]; + JSEvents.deferredCalls.splice(i, 1); --i; call.targetFunction.apply(this, call.argsList); } @@ -125,165 +115,167 @@ var LibraryJsEvents = { eventHandlers: [], _removeHandler: function(i) { - JsEvents.eventHandlers[i].target.removeEventListener(JsEvents.eventHandlers[i].eventTypeString, JsEvents.eventHandlers[i].handlerFunc, true); - JsEvents.eventHandlers.splice(i, 1); + JSEvents.eventHandlers[i].target.removeEventListener(JSEvents.eventHandlers[i].eventTypeString, JSEvents.eventHandlers[i].handlerFunc, true); + JSEvents.eventHandlers.splice(i, 1); }, registerOrRemoveHandler: function(eventHandler) { var jsEventHandler = function jsEventHandler(event) { // Increment nesting count for the event handler. - ++JsEvents.inEventHandler; - JsEvents.currentEventHandler = eventHandler; + ++JSEvents.inEventHandler; + JSEvents.currentEventHandler = eventHandler; // Process any old deferred calls the user has placed. - JsEvents.runDeferredCalls(); + JSEvents.runDeferredCalls(); // Process the actual event, calls back to user C code handler. eventHandler.handlerFunc(event); // Process any new deferred calls that were placed right now from this event handler. - JsEvents.runDeferredCalls(); + JSEvents.runDeferredCalls(); // Out of event handler - restore nesting count. - --JsEvents.inEventHandler; + --JSEvents.inEventHandler; } if (eventHandler.callbackfunc) { eventHandler.target.addEventListener(eventHandler.eventTypeString, jsEventHandler, eventHandler.useCapture); - JsEvents.eventHandlers.push(eventHandler); - JsEvents.registerRemoveEventListeners(); + JSEvents.eventHandlers.push(eventHandler); + JSEvents.registerRemoveEventListeners(); } else { - for(var i = 0; i < JsEvents.eventHandlers.length; ++i) { - if (JsEvents.eventHandlers[i].target == eventHandler.target - && JsEvents.eventHandlers[i].eventTypeString == eventHandler.eventTypeString) { - JsEvents._removeHandler(i--); + for(var i = 0; i < JSEvents.eventHandlers.length; ++i) { + if (JSEvents.eventHandlers[i].target == eventHandler.target + && JSEvents.eventHandlers[i].eventTypeString == eventHandler.eventTypeString) { + JSEvents._removeHandler(i--); } } } }, registerKeyEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { - if (!JsEvents.keyEvent) { - JsEvents.keyEvent = _malloc( {{{ C_STRUCTS.emscripten_KeyboardEvent.__size__ }}} ); + if (!JSEvents.keyEvent) { + JSEvents.keyEvent = _malloc( {{{ C_STRUCTS.EmscriptenKeyboardEvent.__size__ }}} ); } var handlerFunc = function(event) { var e = event || window.event; - writeStringToMemory(e.key ? e.key : "", JsEvents.keyEvent + {{{ C_STRUCTS.emscripten_KeyboardEvent.key }}} ); - writeStringToMemory(e.code ? e.code : "", JsEvents.keyEvent + {{{ C_STRUCTS.emscripten_KeyboardEvent.code }}} ); - {{{ makeSetValue('JsEvents.keyEvent', C_STRUCTS.emscripten_KeyboardEvent.location, 'e.location', 'i32') }}} - {{{ makeSetValue('JsEvents.keyEvent', C_STRUCTS.emscripten_KeyboardEvent.ctrlKey, 'e.ctrlKey', 'i32') }}} - {{{ makeSetValue('JsEvents.keyEvent', C_STRUCTS.emscripten_KeyboardEvent.shiftKey, 'e.shiftKey', 'i32') }}} - {{{ makeSetValue('JsEvents.keyEvent', C_STRUCTS.emscripten_KeyboardEvent.altKey, 'e.altKey', 'i32') }}} - {{{ makeSetValue('JsEvents.keyEvent', C_STRUCTS.emscripten_KeyboardEvent.metaKey, 'e.metaKey', 'i32') }}} - {{{ makeSetValue('JsEvents.keyEvent', C_STRUCTS.emscripten_KeyboardEvent.repeat, 'e.repeat', 'i32') }}} - writeStringToMemory(e.locale ? e.locale : "", JsEvents.keyEvent + {{{ C_STRUCTS.emscripten_KeyboardEvent.locale }}} ); - writeStringToMemory(e.char ? e.char : "", JsEvents.keyEvent + {{{ C_STRUCTS.emscripten_KeyboardEvent.charValue }}} ); - {{{ makeSetValue('JsEvents.keyEvent', C_STRUCTS.emscripten_KeyboardEvent.charCode, 'e.charCode', 'i32') }}} - {{{ makeSetValue('JsEvents.keyEvent', C_STRUCTS.emscripten_KeyboardEvent.keyCode, 'e.keyCode', 'i32') }}} - {{{ makeSetValue('JsEvents.keyEvent', C_STRUCTS.emscripten_KeyboardEvent.which, 'e.which', 'i32') }}} - var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.keyEvent, userData]); + writeStringToMemory(e.key ? e.key : "", JSEvents.keyEvent + {{{ C_STRUCTS.EmscriptenKeyboardEvent.key }}} ); + writeStringToMemory(e.code ? e.code : "", JSEvents.keyEvent + {{{ C_STRUCTS.EmscriptenKeyboardEvent.code }}} ); + {{{ makeSetValue('JSEvents.keyEvent', C_STRUCTS.EmscriptenKeyboardEvent.location, 'e.location', 'i32') }}} + {{{ makeSetValue('JSEvents.keyEvent', C_STRUCTS.EmscriptenKeyboardEvent.ctrlKey, 'e.ctrlKey', 'i32') }}} + {{{ makeSetValue('JSEvents.keyEvent', C_STRUCTS.EmscriptenKeyboardEvent.shiftKey, 'e.shiftKey', 'i32') }}} + {{{ makeSetValue('JSEvents.keyEvent', C_STRUCTS.EmscriptenKeyboardEvent.altKey, 'e.altKey', 'i32') }}} + {{{ makeSetValue('JSEvents.keyEvent', C_STRUCTS.EmscriptenKeyboardEvent.metaKey, 'e.metaKey', 'i32') }}} + {{{ makeSetValue('JSEvents.keyEvent', C_STRUCTS.EmscriptenKeyboardEvent.repeat, 'e.repeat', 'i32') }}} + writeStringToMemory(e.locale ? e.locale : "", JSEvents.keyEvent + {{{ C_STRUCTS.EmscriptenKeyboardEvent.locale }}} ); + writeStringToMemory(e.char ? e.char : "", JSEvents.keyEvent + {{{ C_STRUCTS.EmscriptenKeyboardEvent.charValue }}} ); + {{{ makeSetValue('JSEvents.keyEvent', C_STRUCTS.EmscriptenKeyboardEvent.charCode, 'e.charCode', 'i32') }}} + {{{ makeSetValue('JSEvents.keyEvent', C_STRUCTS.EmscriptenKeyboardEvent.keyCode, 'e.keyCode', 'i32') }}} + {{{ makeSetValue('JSEvents.keyEvent', C_STRUCTS.EmscriptenKeyboardEvent.which, 'e.which', 'i32') }}} + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.keyEvent, userData]); if (shouldCancel) { e.preventDefault(); } }; + var isInternetExplorer = (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') > 0); + var eventHandler = { - target: JsEvents.findEventTarget(target), - allowsDeferredCalls: true, + target: JSEvents.findEventTarget(target), + allowsDeferredCalls: isInternetExplorer ? false : true, // MSIE doesn't allow fullscreen and pointerlock requests from key handlers, others do. eventTypeString: eventTypeString, callbackfunc: callbackfunc, handlerFunc: handlerFunc, useCapture: useCapture }; - JsEvents.registerOrRemoveHandler(eventHandler); + JSEvents.registerOrRemoveHandler(eventHandler); }, fillMouseEventData: function(eventStruct, e) { var rect = Module['canvas'].getBoundingClientRect(); - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.timestamp, 'JsEvents.tick()', 'double') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.screenX, 'e.screenX', 'i32') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.screenY, 'e.screenY', 'i32') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.clientX, 'e.clientX', 'i32') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.clientY, 'e.clientY', 'i32') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.ctrlKey, 'e.ctrlKey', 'i32') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.shiftKey, 'e.shiftKey', 'i32') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.altKey, 'e.altKey', 'i32') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.metaKey, 'e.metaKey', 'i32') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.button, 'e.button', 'i16') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.buttons, 'e.buttons', 'i16') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.movementX, 'e.movementX', 'i32') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.movementY, 'e.movementY', 'i32') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.canvasX, 'e.clientX - rect.left', 'i32') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_MouseEvent.canvasY, 'e.clientY - rect.top', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.timestamp, 'JSEvents.tick()', 'double') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.screenX, 'e.screenX', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.screenY, 'e.screenY', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.clientX, 'e.clientX', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.clientY, 'e.clientY', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.ctrlKey, 'e.ctrlKey', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.shiftKey, 'e.shiftKey', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.altKey, 'e.altKey', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.metaKey, 'e.metaKey', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.button, 'e.button', 'i16') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.buttons, 'e.buttons', 'i16') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.movementX, 'e.movementX', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.movementY, 'e.movementY', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.canvasX, 'e.clientX - rect.left', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.canvasY, 'e.clientY - rect.top', 'i32') }}} }, registerMouseEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { - if (!JsEvents.mouseEvent) { - JsEvents.mouseEvent = _malloc( {{{ C_STRUCTS.emscripten_MouseEvent.__size__ }}} ); + if (!JSEvents.mouseEvent) { + JSEvents.mouseEvent = _malloc( {{{ C_STRUCTS.EmscriptenMouseEvent.__size__ }}} ); } var handlerFunc = function(event) { var e = event || window.event; - JsEvents.fillMouseEventData(JsEvents.mouseEvent, e); - var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.mouseEvent, userData]); + JSEvents.fillMouseEventData(JSEvents.mouseEvent, e); + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.mouseEvent, userData]); if (shouldCancel) { e.preventDefault(); } }; var eventHandler = { - target: JsEvents.findEventTarget(target), + target: JSEvents.findEventTarget(target), allowsDeferredCalls: eventTypeString != 'mousemove', // Mouse move events do not allow fullscreen/pointer lock requests to be handled in them! eventTypeString: eventTypeString, callbackfunc: callbackfunc, handlerFunc: handlerFunc, useCapture: useCapture }; - JsEvents.registerOrRemoveHandler(eventHandler); + JSEvents.registerOrRemoveHandler(eventHandler); }, registerWheelEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { - if (!JsEvents.wheelEvent) { - JsEvents.wheelEvent = _malloc( {{{ C_STRUCTS.emscripten_WheelEvent.__size__ }}} ); + if (!JSEvents.wheelEvent) { + JSEvents.wheelEvent = _malloc( {{{ C_STRUCTS.EmscriptenWheelEvent.__size__ }}} ); } var handlerFunc = function(event) { var e = event || window.event; - JsEvents.fillMouseEventData(JsEvents.wheelEvent, e); - {{{ makeSetValue('JsEvents.wheelEvent', C_STRUCTS.emscripten_WheelEvent.deltaX, 'e.deltaX', 'double') }}} - {{{ makeSetValue('JsEvents.wheelEvent', C_STRUCTS.emscripten_WheelEvent.deltaY, 'e.deltaY', 'double') }}} - {{{ makeSetValue('JsEvents.wheelEvent', C_STRUCTS.emscripten_WheelEvent.deltaZ, 'e.deltaZ', 'double') }}} - {{{ makeSetValue('JsEvents.wheelEvent', C_STRUCTS.emscripten_WheelEvent.deltaMode, 'e.deltaMode', 'i32') }}} - var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.wheelEvent, userData]); + JSEvents.fillMouseEventData(JSEvents.wheelEvent, e); + {{{ makeSetValue('JSEvents.wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaX, 'e.deltaX', 'double') }}} + {{{ makeSetValue('JSEvents.wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaY, 'e.deltaY', 'double') }}} + {{{ makeSetValue('JSEvents.wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaZ, 'e.deltaZ', 'double') }}} + {{{ makeSetValue('JSEvents.wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaMode, 'e.deltaMode', 'i32') }}} + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.wheelEvent, userData]); if (shouldCancel) { e.preventDefault(); } }; var eventHandler = { - target: JsEvents.findEventTarget(target), + target: JSEvents.findEventTarget(target), allowsDeferredCalls: true, eventTypeString: eventTypeString, callbackfunc: callbackfunc, handlerFunc: handlerFunc, useCapture: useCapture }; - JsEvents.registerOrRemoveHandler(eventHandler); + JSEvents.registerOrRemoveHandler(eventHandler); }, pageScrollPos: function() { if (window.pageXOffset > 0 || window.pageYOffset > 0) { return [window.pageXOffset, window.pageYOffset]; } - if (document.documentElement.scrollLeft > 0 || document.documentElement.scrollTop > 0) { + if (typeof document.documentElement.scrollLeft !== 'undefined' || typeof document.documentElement.scrollTop !== 'undefined') { return [document.documentElement.scrollLeft, document.documentElement.scrollTop]; } return [document.body.scrollLeft|0, document.body.scrollTop|0]; }, registerUiEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { - if (!JsEvents.uiEvent) { - JsEvents.uiEvent = _malloc( {{{ C_STRUCTS.emscripten_UiEvent.__size__ }}} ); + if (!JSEvents.uiEvent) { + JSEvents.uiEvent = _malloc( {{{ C_STRUCTS.EmscriptenUiEvent.__size__ }}} ); } if (eventTypeString == "scroll" && !target) { target = document; // By default read scroll events on document rather than window. } else { - target = JsEvents.findEventTarget(target); + target = JSEvents.findEventTarget(target); } var handlerFunc = function(event) { @@ -295,17 +287,17 @@ var LibraryJsEvents = { // causing a new scroll, etc.. return; } - var scrollPos = JsEvents.pageScrollPos(); - {{{ makeSetValue('JsEvents.uiEvent', C_STRUCTS.emscripten_UiEvent.detail, 'e.detail', 'i32') }}} - {{{ makeSetValue('JsEvents.uiEvent', C_STRUCTS.emscripten_UiEvent.documentBodyClientWidth, 'document.body.clientWidth', 'i32') }}} - {{{ makeSetValue('JsEvents.uiEvent', C_STRUCTS.emscripten_UiEvent.documentBodyClientHeight, 'document.body.clientHeight', 'i32') }}} - {{{ makeSetValue('JsEvents.uiEvent', C_STRUCTS.emscripten_UiEvent.windowInnerWidth, 'window.innerWidth', 'i32') }}} - {{{ makeSetValue('JsEvents.uiEvent', C_STRUCTS.emscripten_UiEvent.windowInnerHeight, 'window.innerHeight', 'i32') }}} - {{{ makeSetValue('JsEvents.uiEvent', C_STRUCTS.emscripten_UiEvent.windowOuterWidth, 'window.outerWidth', 'i32') }}} - {{{ makeSetValue('JsEvents.uiEvent', C_STRUCTS.emscripten_UiEvent.windowOuterHeight, 'window.outerHeight', 'i32') }}} - {{{ makeSetValue('JsEvents.uiEvent', C_STRUCTS.emscripten_UiEvent.scrollTop, 'scrollPos[0]', 'i32') }}} - {{{ makeSetValue('JsEvents.uiEvent', C_STRUCTS.emscripten_UiEvent.scrollLeft, 'scrollPos[1]', 'i32') }}} - var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.uiEvent, userData]); + var scrollPos = JSEvents.pageScrollPos(); + {{{ makeSetValue('JSEvents.uiEvent', C_STRUCTS.EmscriptenUiEvent.detail, 'e.detail', 'i32') }}} + {{{ makeSetValue('JSEvents.uiEvent', C_STRUCTS.EmscriptenUiEvent.documentBodyClientWidth, 'document.body.clientWidth', 'i32') }}} + {{{ makeSetValue('JSEvents.uiEvent', C_STRUCTS.EmscriptenUiEvent.documentBodyClientHeight, 'document.body.clientHeight', 'i32') }}} + {{{ makeSetValue('JSEvents.uiEvent', C_STRUCTS.EmscriptenUiEvent.windowInnerWidth, 'window.innerWidth', 'i32') }}} + {{{ makeSetValue('JSEvents.uiEvent', C_STRUCTS.EmscriptenUiEvent.windowInnerHeight, 'window.innerHeight', 'i32') }}} + {{{ makeSetValue('JSEvents.uiEvent', C_STRUCTS.EmscriptenUiEvent.windowOuterWidth, 'window.outerWidth', 'i32') }}} + {{{ makeSetValue('JSEvents.uiEvent', C_STRUCTS.EmscriptenUiEvent.windowOuterHeight, 'window.outerHeight', 'i32') }}} + {{{ makeSetValue('JSEvents.uiEvent', C_STRUCTS.EmscriptenUiEvent.scrollTop, 'scrollPos[0]', 'i32') }}} + {{{ makeSetValue('JSEvents.uiEvent', C_STRUCTS.EmscriptenUiEvent.scrollLeft, 'scrollPos[1]', 'i32') }}} + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.uiEvent, userData]); if (shouldCancel) { e.preventDefault(); } @@ -319,154 +311,150 @@ var LibraryJsEvents = { handlerFunc: handlerFunc, useCapture: useCapture }; - JsEvents.registerOrRemoveHandler(eventHandler); + JSEvents.registerOrRemoveHandler(eventHandler); }, getNodeNameForTarget: function(target) { - if (!target) { - return ''; - } - if (target == window) { - return '#window'; - } - if (target == window.screen) { - return '#screen'; - } + if (!target) return ''; + if (target == window) return '#window'; + if (target == window.screen) return '#screen'; return (target && target.nodeName) ? target.nodeName : ''; }, registerFocusEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { - if (!JsEvents.focusEvent) { - JsEvents.focusEvent = _malloc( {{{ C_STRUCTS.emscripten_FocusEvent.__size__ }}} ); + if (!JSEvents.focusEvent) { + JSEvents.focusEvent = _malloc( {{{ C_STRUCTS.EmscriptenFocusEvent.__size__ }}} ); } var handlerFunc = function(event) { var e = event || window.event; - var nodeName = JsEvents.getNodeNameForTarget(e.target); + var nodeName = JSEvents.getNodeNameForTarget(e.target); var id = e.target.id ? e.target.id : ''; - writeStringToMemory(nodeName, JsEvents.focusEvent + {{{ C_STRUCTS.emscripten_FocusEvent.nodeName }}} ); - writeStringToMemory(id, JsEvents.focusEvent + {{{ C_STRUCTS.emscripten_FocusEvent.id }}} ); - var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.focusEvent, userData]); + writeStringToMemory(nodeName, JSEvents.focusEvent + {{{ C_STRUCTS.EmscriptenFocusEvent.nodeName }}} ); + writeStringToMemory(id, JSEvents.focusEvent + {{{ C_STRUCTS.EmscriptenFocusEvent.id }}} ); + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.focusEvent, userData]); if (shouldCancel) { e.preventDefault(); } }; var eventHandler = { - target: JsEvents.findEventTarget(target), + target: JSEvents.findEventTarget(target), allowsDeferredCalls: false, eventTypeString: eventTypeString, callbackfunc: callbackfunc, handlerFunc: handlerFunc, useCapture: useCapture }; - JsEvents.registerOrRemoveHandler(eventHandler); + JSEvents.registerOrRemoveHandler(eventHandler); }, tick: function() { - if (window['performance'] && window['performance']['now']) { - return window['performance']['now'](); - } else { - return Date.now(); - } + if (window['performance'] && window['performance']['now']) return window['performance']['now'](); + else return Date.now(); }, registerDeviceOrientationEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { - if (!JsEvents.deviceOrientationEvent) { - JsEvents.deviceOrientationEvent = _malloc( {{{ C_STRUCTS.emscripten_DeviceOrientationEvent.__size__ }}} ); + if (!JSEvents.deviceOrientationEvent) { + JSEvents.deviceOrientationEvent = _malloc( {{{ C_STRUCTS.EmscriptenDeviceOrientationEvent.__size__ }}} ); } var handlerFunc = function(event) { var e = event || window.event; - {{{ makeSetValue('JsEvents.deviceOrientationEvent', C_STRUCTS.emscripten_DeviceOrientationEvent.timestamp, 'JsEvents.tick()', 'double') }}} - {{{ makeSetValue('JsEvents.deviceOrientationEvent', C_STRUCTS.emscripten_DeviceOrientationEvent.alpha, 'e.alpha', 'double') }}} - {{{ makeSetValue('JsEvents.deviceOrientationEvent', C_STRUCTS.emscripten_DeviceOrientationEvent.beta, 'e.beta', 'double') }}} - {{{ makeSetValue('JsEvents.deviceOrientationEvent', C_STRUCTS.emscripten_DeviceOrientationEvent.gamma, 'e.gamma', 'double') }}} - {{{ makeSetValue('JsEvents.deviceOrientationEvent', C_STRUCTS.emscripten_DeviceOrientationEvent.absolute, 'e.absolute', 'i32') }}} + {{{ makeSetValue('JSEvents.deviceOrientationEvent', C_STRUCTS.EmscriptenDeviceOrientationEvent.timestamp, 'JSEvents.tick()', 'double') }}} + {{{ makeSetValue('JSEvents.deviceOrientationEvent', C_STRUCTS.EmscriptenDeviceOrientationEvent.alpha, 'e.alpha', 'double') }}} + {{{ makeSetValue('JSEvents.deviceOrientationEvent', C_STRUCTS.EmscriptenDeviceOrientationEvent.beta, 'e.beta', 'double') }}} + {{{ makeSetValue('JSEvents.deviceOrientationEvent', C_STRUCTS.EmscriptenDeviceOrientationEvent.gamma, 'e.gamma', 'double') }}} + {{{ makeSetValue('JSEvents.deviceOrientationEvent', C_STRUCTS.EmscriptenDeviceOrientationEvent.absolute, 'e.absolute', 'i32') }}} - var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.deviceOrientationEvent, userData]); + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.deviceOrientationEvent, userData]); if (shouldCancel) { e.preventDefault(); } }; var eventHandler = { - target: JsEvents.findEventTarget(target), + target: JSEvents.findEventTarget(target), allowsDeferredCalls: false, eventTypeString: eventTypeString, callbackfunc: callbackfunc, handlerFunc: handlerFunc, useCapture: useCapture }; - JsEvents.registerOrRemoveHandler(eventHandler); + JSEvents.registerOrRemoveHandler(eventHandler); }, registerDeviceMotionEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { - if (!JsEvents.deviceMotionEvent) { - JsEvents.deviceMotionEvent = _malloc( {{{ C_STRUCTS.emscripten_DeviceMotionEvent.__size__ }}} ); + if (!JSEvents.deviceMotionEvent) { + JSEvents.deviceMotionEvent = _malloc( {{{ C_STRUCTS.EmscriptenDeviceMotionEvent.__size__ }}} ); } var handlerFunc = function(event) { var e = event || window.event; - {{{ makeSetValue('JsEvents.deviceOrientationEvent', C_STRUCTS.emscripten_DeviceMotionEvent.timestamp, 'JsEvents.tick()', 'double') }}} - {{{ makeSetValue('JsEvents.deviceMotionEvent', C_STRUCTS.emscripten_DeviceMotionEvent.accelerationX, 'e.acceleration.x', 'double') }}} - {{{ makeSetValue('JsEvents.deviceMotionEvent', C_STRUCTS.emscripten_DeviceMotionEvent.accelerationY, 'e.acceleration.y', 'double') }}} - {{{ makeSetValue('JsEvents.deviceMotionEvent', C_STRUCTS.emscripten_DeviceMotionEvent.accelerationZ, 'e.acceleration.z', 'double') }}} - {{{ makeSetValue('JsEvents.deviceMotionEvent', C_STRUCTS.emscripten_DeviceMotionEvent.accelerationIncludingGravityX, 'e.accelerationIncludingGravity.x', 'double') }}} - {{{ makeSetValue('JsEvents.deviceMotionEvent', C_STRUCTS.emscripten_DeviceMotionEvent.accelerationIncludingGravityY, 'e.accelerationIncludingGravity.y', 'double') }}} - {{{ makeSetValue('JsEvents.deviceMotionEvent', C_STRUCTS.emscripten_DeviceMotionEvent.accelerationIncludingGravityZ, 'e.accelerationIncludingGravity.z', 'double') }}} - {{{ makeSetValue('JsEvents.deviceMotionEvent', C_STRUCTS.emscripten_DeviceMotionEvent.rotationRateAlpha, 'e.rotationRate.alpha', 'double') }}} - {{{ makeSetValue('JsEvents.deviceMotionEvent', C_STRUCTS.emscripten_DeviceMotionEvent.rotationRateBeta, 'e.rotationRate.beta', 'double') }}} - {{{ makeSetValue('JsEvents.deviceMotionEvent', C_STRUCTS.emscripten_DeviceMotionEvent.rotationRateGamma, 'e.rotationRate.gamma', 'double') }}} + {{{ makeSetValue('JSEvents.deviceOrientationEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.timestamp, 'JSEvents.tick()', 'double') }}} + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationX, 'e.acceleration.x', 'double') }}} + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationY, 'e.acceleration.y', 'double') }}} + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationZ, 'e.acceleration.z', 'double') }}} + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationIncludingGravityX, 'e.accelerationIncludingGravity.x', 'double') }}} + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationIncludingGravityY, 'e.accelerationIncludingGravity.y', 'double') }}} + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationIncludingGravityZ, 'e.accelerationIncludingGravity.z', 'double') }}} + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.rotationRateAlpha, 'e.rotationRate.alpha', 'double') }}} + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.rotationRateBeta, 'e.rotationRate.beta', 'double') }}} + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.rotationRateGamma, 'e.rotationRate.gamma', 'double') }}} - var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.deviceMotionEvent, userData]); + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.deviceMotionEvent, userData]); if (shouldCancel) { e.preventDefault(); } }; var eventHandler = { - target: JsEvents.findEventTarget(target), + target: JSEvents.findEventTarget(target), allowsDeferredCalls: false, eventTypeString: eventTypeString, callbackfunc: callbackfunc, handlerFunc: handlerFunc, useCapture: useCapture }; - JsEvents.registerOrRemoveHandler(eventHandler); + JSEvents.registerOrRemoveHandler(eventHandler); + }, + + screenOrientation: function() { + if (!window.screen) return undefined; + return window.screen.orientation || window.screen.mozOrientation || window.screen.webkitOrientation || window.screen.msOrientation; }, fillOrientationChangeEventData: function(eventStruct, e) { var orientations = ["portrait-primary", "portrait-secondary", "landscape-primary", "landscape-secondary"]; var orientations2 = ["portrait", "portrait", "landscape", "landscape"]; - var orientationString = window.screen.orientation || window.screen.mozOrientation; + var orientationString = JSEvents.screenOrientation(); var orientation = orientations.indexOf(orientationString); if (orientation == -1) { orientation = orientations2.indexOf(orientationString); } - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_OrientationChangeEvent.orientationIndex, '1 << orientation', 'i32') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_OrientationChangeEvent.orientationAngle, 'window.orientation', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenOrientationChangeEvent.orientationIndex, '1 << orientation', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenOrientationChangeEvent.orientationAngle, 'window.orientation', 'i32') }}} }, registerOrientationChangeEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { - if (!JsEvents.orientationChangeEvent) { - JsEvents.orientationChangeEvent = _malloc( {{{ C_STRUCTS.emscripten_OrientationChangeEvent.__size__ }}} ); + if (!JSEvents.orientationChangeEvent) { + JSEvents.orientationChangeEvent = _malloc( {{{ C_STRUCTS.EmscriptenOrientationChangeEvent.__size__ }}} ); } if (!target) { target = window.screen; // Orientation events need to be captured from 'window.screen' instead of 'window' } else { - target = JsEvents.findEventTarget(target); + target = JSEvents.findEventTarget(target); } var handlerFunc = function(event) { var e = event || window.event; - JsEvents.fillOrientationChangeEventData(JsEvents.orientationChangeEvent, e); + JSEvents.fillOrientationChangeEventData(JSEvents.orientationChangeEvent, e); - var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.orientationChangeEvent, userData]); + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.orientationChangeEvent, userData]); if (shouldCancel) { e.preventDefault(); } @@ -484,37 +472,41 @@ var LibraryJsEvents = { handlerFunc: handlerFunc, useCapture: useCapture }; - JsEvents.registerOrRemoveHandler(eventHandler); + JSEvents.registerOrRemoveHandler(eventHandler); }, + fullscreenEnabled: function() { + return document.fullscreenEnabled || document.mozFullscreenEnabled || document.mozFullScreenEnabled || document.webkitFullscreenEnabled || document.msFullscreenEnabled; + }, + fillFullscreenChangeEventData: function(eventStruct, e) { var fullscreenElement = document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement; var isFullscreen = !!fullscreenElement; - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_FullscreenChangeEvent.isFullscreen, 'isFullscreen', 'i32') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_FullscreenChangeEvent.fullscreenEnabled, 'document.fullscreenEnabled', 'i32') }}} - var nodeName = JsEvents.getNodeNameForTarget(fullscreenElement); + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.isFullscreen, 'isFullscreen', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.fullscreenEnabled, 'JSEvents.fullscreenEnabled()', 'i32') }}} + var nodeName = JSEvents.getNodeNameForTarget(fullscreenElement); var id = (fullscreenElement && fullscreenElement.id) ? fullscreenElement.id : ''; - writeStringToMemory(nodeName, eventStruct + {{{ C_STRUCTS.emscripten_FullscreenChangeEvent.nodeName }}} ); - writeStringToMemory(id, eventStruct + {{{ C_STRUCTS.emscripten_FullscreenChangeEvent.id }}} ); + writeStringToMemory(nodeName, eventStruct + {{{ C_STRUCTS.EmscriptenFullscreenChangeEvent.nodeName }}} ); + writeStringToMemory(id, eventStruct + {{{ C_STRUCTS.EmscriptenFullscreenChangeEvent.id }}} ); }, registerFullscreenChangeEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { - if (!JsEvents.fullscreenChangeEvent) { - JsEvents.fullscreenChangeEvent = _malloc( {{{ C_STRUCTS.emscripten_FullscreenChangeEvent.__size__ }}} ); + if (!JSEvents.fullscreenChangeEvent) { + JSEvents.fullscreenChangeEvent = _malloc( {{{ C_STRUCTS.EmscriptenFullscreenChangeEvent.__size__ }}} ); } if (!target) { target = document; // Fullscreen change events need to be captured from 'document' by default instead of 'window' } else { - target = JsEvents.findEventTarget(target); + target = JSEvents.findEventTarget(target); } var handlerFunc = function(event) { var e = event || window.event; - JsEvents.fillFullscreenChangeEventData(JsEvents.fullscreenChangeEvent, e); + JSEvents.fillFullscreenChangeEventData(JSEvents.fullscreenChangeEvent, e); - var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.fullscreenChangeEvent, userData]); + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.fullscreenChangeEvent, userData]); if (shouldCancel) { e.preventDefault(); } @@ -528,7 +520,7 @@ var LibraryJsEvents = { handlerFunc: handlerFunc, useCapture: useCapture }; - JsEvents.registerOrRemoveHandler(eventHandler); + JSEvents.registerOrRemoveHandler(eventHandler); }, requestFullscreen: function(target) { @@ -538,10 +530,16 @@ var LibraryJsEvents = { target.msRequestFullscreen(); } else if (target.mozRequestFullScreen) { target.mozRequestFullScreen(); + } else if (target.mozRequestFullscreen) { + target.mozRequestFullscreen(); } else if (target.webkitRequestFullscreen) { target.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); } else { - return 2 /* Target does not support requesting fullscreen */; + if (typeof JSEvents.fullscreenEnabled() === 'undefined') { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } else { + return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + } } return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, @@ -549,30 +547,30 @@ var LibraryJsEvents = { fillPointerlockChangeEventData: function(eventStruct, e) { var pointerLockElement = document.pointerLockElement || document.mozPointerLockElement || document.webkitPointerLockElement || document.msPointerLockElement; var isPointerlocked = !!pointerLockElement; - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_PointerlockChangeEvent.isActive, 'isPointerlocked', 'i32') }}} - var nodeName = JsEvents.getNodeNameForTarget(pointerLockElement); + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenPointerlockChangeEvent.isActive, 'isPointerlocked', 'i32') }}} + var nodeName = JSEvents.getNodeNameForTarget(pointerLockElement); var id = (pointerLockElement && pointerLockElement.id) ? pointerLockElement.id : ''; - writeStringToMemory(nodeName, eventStruct + {{{ C_STRUCTS.emscripten_PointerlockChangeEvent.nodeName }}} ); - writeStringToMemory(id, eventStruct + {{{ C_STRUCTS.emscripten_PointerlockChangeEvent.id }}}); + writeStringToMemory(nodeName, eventStruct + {{{ C_STRUCTS.EmscriptenPointerlockChangeEvent.nodeName }}} ); + writeStringToMemory(id, eventStruct + {{{ C_STRUCTS.EmscriptenPointerlockChangeEvent.id }}}); }, registerPointerlockChangeEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { - if (!JsEvents.pointerlockChangeEvent) { - JsEvents.pointerlockChangeEvent = _malloc( {{{ C_STRUCTS.emscripten_PointerlockChangeEvent.__size__ }}} ); + if (!JSEvents.pointerlockChangeEvent) { + JSEvents.pointerlockChangeEvent = _malloc( {{{ C_STRUCTS.EmscriptenPointerlockChangeEvent.__size__ }}} ); } if (!target) { target = document; // Pointer lock change events need to be captured from 'document' by default instead of 'window' } else { - target = JsEvents.findEventTarget(target); + target = JSEvents.findEventTarget(target); } var handlerFunc = function(event) { var e = event || window.event; - JsEvents.fillPointerlockChangeEventData(JsEvents.pointerlockChangeEvent, e); + JSEvents.fillPointerlockChangeEventData(JSEvents.pointerlockChangeEvent, e); - var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.pointerlockChangeEvent, userData]); + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.pointerlockChangeEvent, userData]); if (shouldCancel) { e.preventDefault(); } @@ -586,7 +584,7 @@ var LibraryJsEvents = { handlerFunc: handlerFunc, useCapture: useCapture }; - JsEvents.registerOrRemoveHandler(eventHandler); + JSEvents.registerOrRemoveHandler(eventHandler); }, requestPointerLock: function(target) { @@ -599,7 +597,13 @@ var LibraryJsEvents = { } else if (target.msRequestPointerLock) { target.msRequestPointerLock(); } else { - return 2 /* Target does not support requesting pointer lock */; + // document.body is known to accept pointer lock, so use that to differentiate if the user passed a bad element, + // or if the whole browser just doesn't support the feature. + if (document.body.requestPointerLock || document.body.mozRequestPointerLock || document.body.webkitRequestPointerLock || document.body.msRequestPointerLock) { + return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + } else { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } } return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, @@ -608,27 +612,27 @@ var LibraryJsEvents = { var visibilityStates = [ "hidden", "visible", "prerender", "unloaded" ]; var visibilityState = visibilityStates.indexOf(document.visibilityState); - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_VisibilityChangeEvent.hidden, 'document.hidden', 'i32') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_VisibilityChangeEvent.visibilityState, 'visibilityState', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenVisibilityChangeEvent.hidden, 'document.hidden', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenVisibilityChangeEvent.visibilityState, 'visibilityState', 'i32') }}} }, registerVisibilityChangeEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { - if (!JsEvents.visibilityChangeEvent) { - JsEvents.visibilityChangeEvent = _malloc( {{{ C_STRUCTS.emscripten_VisibilityChangeEvent.__size__ }}} ); + if (!JSEvents.visibilityChangeEvent) { + JSEvents.visibilityChangeEvent = _malloc( {{{ C_STRUCTS.EmscriptenVisibilityChangeEvent.__size__ }}} ); } if (!target) { target = document; // Visibility change events need to be captured from 'document' by default instead of 'window' } else { - target = JsEvents.findEventTarget(target); + target = JSEvents.findEventTarget(target); } var handlerFunc = function(event) { var e = event || window.event; - JsEvents.fillVisibilityChangeEventData(JsEvents.visibilityChangeEvent, e); + JSEvents.fillVisibilityChangeEventData(JSEvents.visibilityChangeEvent, e); - var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.visibilityChangeEvent, userData]); + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.visibilityChangeEvent, userData]); if (shouldCancel) { e.preventDefault(); } @@ -642,12 +646,12 @@ var LibraryJsEvents = { handlerFunc: handlerFunc, useCapture: useCapture }; - JsEvents.registerOrRemoveHandler(eventHandler); + JSEvents.registerOrRemoveHandler(eventHandler); }, registerTouchEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { - if (!JsEvents.touchEvent) { - JsEvents.touchEvent = _malloc( {{{ C_STRUCTS.emscripten_TouchEvent.__size__ }}} ); + if (!JSEvents.touchEvent) { + JSEvents.touchEvent = _malloc( {{{ C_STRUCTS.EmscriptenTouchEvent.__size__ }}} ); } var handlerFunc = function(event) { @@ -668,96 +672,96 @@ var LibraryJsEvents = { touches[touch.identifier].onTarget = true; } - var ptr = JsEvents.touchEvent; - {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchEvent.ctrlKey, 'e.ctrlKey', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchEvent.shiftKey, 'e.shiftKey', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchEvent.altKey, 'e.altKey', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchEvent.metaKey, 'e.metaKey', 'i32') }}} - ptr += {{{ C_STRUCTS.emscripten_TouchEvent.touches }}}; // Advance to the start of the touch array. + var ptr = JSEvents.touchEvent; + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchEvent.ctrlKey, 'e.ctrlKey', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchEvent.shiftKey, 'e.shiftKey', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchEvent.altKey, 'e.altKey', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchEvent.metaKey, 'e.metaKey', 'i32') }}} + ptr += {{{ C_STRUCTS.EmscriptenTouchEvent.touches }}}; // Advance to the start of the touch array. var rect = Module['canvas'].getBoundingClientRect(); var numTouches = 0; for(var i in touches) { var t = touches[i]; - {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.identifier, 't.identifier', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.screenX, 't.screenX', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.screenY, 't.screenY', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.clientX, 't.clientX', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.clientY, 't.clientY', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.pageX, 't.pageX', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.pageY, 't.pageY', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.isChanged, 't.changed', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.onTarget, 't.onTarget', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.canvasX, 't.clientX - rect.left', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.emscripten_TouchPoint.canvasY, 't.clientY - rect.top', 'i32') }}} - ptr += {{{ C_STRUCTS.emscripten_TouchPoint.__size__ }}}; + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.identifier, 't.identifier', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.screenX, 't.screenX', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.screenY, 't.screenY', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.clientX, 't.clientX', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.clientY, 't.clientY', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.pageX, 't.pageX', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.pageY, 't.pageY', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.isChanged, 't.changed', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.onTarget, 't.onTarget', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.canvasX, 't.clientX - rect.left', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.canvasY, 't.clientY - rect.top', 'i32') }}} + ptr += {{{ C_STRUCTS.EmscriptenTouchPoint.__size__ }}}; if (++numTouches >= 32) { break; } } - {{{ makeSetValue('JsEvents.touchEvent', C_STRUCTS.emscripten_TouchEvent.numTouches, 'numTouches', 'i32') }}} + {{{ makeSetValue('JSEvents.touchEvent', C_STRUCTS.EmscriptenTouchEvent.numTouches, 'numTouches', 'i32') }}} - var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.touchEvent, userData]); + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.touchEvent, userData]); if (shouldCancel) { e.preventDefault(); } }; var eventHandler = { - target: JsEvents.findEventTarget(target), + target: JSEvents.findEventTarget(target), allowsDeferredCalls: true, eventTypeString: eventTypeString, callbackfunc: callbackfunc, handlerFunc: handlerFunc, useCapture: useCapture }; - JsEvents.registerOrRemoveHandler(eventHandler); + JSEvents.registerOrRemoveHandler(eventHandler); }, fillGamepadEventData: function(eventStruct, e) { - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_GamepadEvent.timestamp, 'e.timestamp', 'double') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.timestamp, 'e.timestamp', 'double') }}} for(var i = 0; i < e.axes.length; ++i) { - {{{ makeSetValue('eventStruct+i*8', C_STRUCTS.emscripten_GamepadEvent.axis, 'e.axes[i]', 'double') }}} + {{{ makeSetValue('eventStruct+i*8', C_STRUCTS.EmscriptenGamepadEvent.axis, 'e.axes[i]', 'double') }}} } for(var i = 0; i < e.buttons.length; ++i) { - {{{ makeSetValue('eventStruct+i*8', C_STRUCTS.emscripten_GamepadEvent.analogButton, 'e.buttons[i].value', 'double') }}} + {{{ makeSetValue('eventStruct+i*8', C_STRUCTS.EmscriptenGamepadEvent.analogButton, 'e.buttons[i].value', 'double') }}} } for(var i = 0; i < e.buttons.length; ++i) { - {{{ makeSetValue('eventStruct+i*4', C_STRUCTS.emscripten_GamepadEvent.digitalButton, 'e.buttons[i].pressed', 'i32') }}} + {{{ makeSetValue('eventStruct+i*4', C_STRUCTS.EmscriptenGamepadEvent.digitalButton, 'e.buttons[i].pressed', 'i32') }}} } - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_GamepadEvent.connected, 'e.connected', 'i32') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_GamepadEvent.index, 'e.index', 'i32') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_GamepadEvent.numAxes, 'e.axes.length', 'i32') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_GamepadEvent.numButtons, 'e.buttons.length', 'i32') }}} - writeStringToMemory(e.id, eventStruct + {{{ C_STRUCTS.emscripten_GamepadEvent.id }}} ); - writeStringToMemory(e.mapping, eventStruct + {{{ C_STRUCTS.emscripten_GamepadEvent.mapping }}} ); + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.connected, 'e.connected', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.index, 'e.index', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.numAxes, 'e.axes.length', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.numButtons, 'e.buttons.length', 'i32') }}} + writeStringToMemory(e.id, eventStruct + {{{ C_STRUCTS.EmscriptenGamepadEvent.id }}} ); + writeStringToMemory(e.mapping, eventStruct + {{{ C_STRUCTS.EmscriptenGamepadEvent.mapping }}} ); }, registerGamepadEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { - if (!JsEvents.gamepadEvent) { - JsEvents.gamepadEvent = _malloc( {{{ C_STRUCTS.emscripten_GamepadEvent.__size__ }}} ); + if (!JSEvents.gamepadEvent) { + JSEvents.gamepadEvent = _malloc( {{{ C_STRUCTS.EmscriptenGamepadEvent.__size__ }}} ); } var handlerFunc = function(event) { var e = event || window.event; - JsEvents.fillGamepadEventData(JsEvents.gamepadEvent, e.gamepad); + JSEvents.fillGamepadEventData(JSEvents.gamepadEvent, e.gamepad); - var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.gamepadEvent, userData]); + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.gamepadEvent, userData]); if (shouldCancel) { e.preventDefault(); } }; var eventHandler = { - target: JsEvents.findEventTarget(target), + target: JSEvents.findEventTarget(target), allowsDeferredCalls: true, eventTypeString: eventTypeString, callbackfunc: callbackfunc, handlerFunc: handlerFunc, useCapture: useCapture }; - JsEvents.registerOrRemoveHandler(eventHandler); + JSEvents.registerOrRemoveHandler(eventHandler); }, registerBeforeUnloadEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { @@ -775,50 +779,50 @@ var LibraryJsEvents = { }; var eventHandler = { - target: JsEvents.findEventTarget(target), + target: JSEvents.findEventTarget(target), allowsDeferredCalls: false, eventTypeString: eventTypeString, callbackfunc: callbackfunc, handlerFunc: handlerFunc, useCapture: useCapture }; - JsEvents.registerOrRemoveHandler(eventHandler); + JSEvents.registerOrRemoveHandler(eventHandler); }, battery: function() { return navigator.battery || navigator.mozBattery || navigator.webkitBattery; }, fillBatteryEventData: function(eventStruct, e) { - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_BatteryEvent.chargingTime, 'e.chargingTime', 'double') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_BatteryEvent.dischargingTime, 'e.dischargingTime', 'double') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_BatteryEvent.level, 'e.level', 'double') }}} - {{{ makeSetValue('eventStruct', C_STRUCTS.emscripten_BatteryEvent.charging, 'e.charging', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenBatteryEvent.chargingTime, 'e.chargingTime', 'double') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenBatteryEvent.dischargingTime, 'e.dischargingTime', 'double') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenBatteryEvent.level, 'e.level', 'double') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenBatteryEvent.charging, 'e.charging', 'i32') }}} }, registerBatteryEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { - if (!JsEvents.batteryEvent) { - JsEvents.batteryEvent = _malloc( {{{ C_STRUCTS.emscripten_BatteryEvent.__size__ }}} ); + if (!JSEvents.batteryEvent) { + JSEvents.batteryEvent = _malloc( {{{ C_STRUCTS.EmscriptenBatteryEvent.__size__ }}} ); } var handlerFunc = function(event) { var e = event || window.event; - JsEvents.fillBatteryEventData(JsEvents.batteryEvent, JsEvents.battery()); + JSEvents.fillBatteryEventData(JSEvents.batteryEvent, JSEvents.battery()); - var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JsEvents.batteryEvent, userData]); + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.batteryEvent, userData]); if (shouldCancel) { e.preventDefault(); } }; var eventHandler = { - target: JsEvents.findEventTarget(target), + target: JSEvents.findEventTarget(target), allowsDeferredCalls: false, eventTypeString: eventTypeString, callbackfunc: callbackfunc, handlerFunc: handlerFunc, useCapture: useCapture }; - JsEvents.registerOrRemoveHandler(eventHandler); + JSEvents.registerOrRemoveHandler(eventHandler); }, registerWebGlEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { @@ -835,145 +839,138 @@ var LibraryJsEvents = { }; var eventHandler = { - target: JsEvents.findEventTarget(target), + target: JSEvents.findEventTarget(target), allowsDeferredCalls: false, eventTypeString: eventTypeString, callbackfunc: callbackfunc, handlerFunc: handlerFunc, useCapture: useCapture }; - JsEvents.registerOrRemoveHandler(eventHandler); + JSEvents.registerOrRemoveHandler(eventHandler); }, }, emscripten_set_keypress_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_KEYPRESS') }}}, "keypress"); + JSEvents.registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_KEYPRESS') }}}, "keypress"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_keydown_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_KEYDOWN') }}}, "keydown"); + JSEvents.registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_KEYDOWN') }}}, "keydown"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_keyup_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_KEYUP') }}}, "keyup"); + JSEvents.registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_KEYUP') }}}, "keyup"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_click_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_CLICK') }}}, "click"); + JSEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_CLICK') }}}, "click"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_mousedown_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEDOWN') }}}, "mousedown"); + JSEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEDOWN') }}}, "mousedown"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_mouseup_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEUP') }}}, "mouseup"); + JSEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEUP') }}}, "mouseup"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_dblclick_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_DBLCLICK') }}}, "dblclick"); + JSEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_DBLCLICK') }}}, "dblclick"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_mousemove_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEMOVE') }}}, "mousemove"); + JSEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEMOVE') }}}, "mousemove"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_get_mouse_status: function(mouseState) { - if (!JsEvents.mouseEvent) { - return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; - } + if (!JSEvents.mouseEvent) return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; // HTML5 does not really have a polling API for mouse events, so implement one manually by // returning the data from the most recently received event. This requires that user has registered // at least some no-op function as an event handler to any of the mouse function. - HEAP32.set(HEAP32.subarray(JsEvents.mouseEvent, {{{ C_STRUCTS.emscripten_MouseEvent.__size__ }}}), mouseState); + HEAP32.set(HEAP32.subarray(JSEvents.mouseEvent, {{{ C_STRUCTS.EmscriptenMouseEvent.__size__ }}}), mouseState); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_wheel_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerWheelEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WHEEL') }}}, "wheel"); + JSEvents.registerWheelEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WHEEL') }}}, "wheel"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_resize_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_RESIZE') }}}, "resize"); + JSEvents.registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_RESIZE') }}}, "resize"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_scroll_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_SCROLL') }}}, "scroll"); + JSEvents.registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_SCROLL') }}}, "scroll"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_blur_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BLUR') }}}, "blur"); + JSEvents.registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BLUR') }}}, "blur"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_focus_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FOCUS') }}}, "focus"); + JSEvents.registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FOCUS') }}}, "focus"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_focusin_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FOCUSIN') }}}, "focusin"); + JSEvents.registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FOCUSIN') }}}, "focusin"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_focusout_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FOCUSOUT') }}}, "focusout"); + JSEvents.registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FOCUSOUT') }}}, "focusout"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_deviceorientation_callback: function(userData, useCapture, callbackfunc) { - JsEvents.registerDeviceOrientationEventCallback(window, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_DEVICEORIENTATION') }}}, "deviceorientation"); + JSEvents.registerDeviceOrientationEventCallback(window, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_DEVICEORIENTATION') }}}, "deviceorientation"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_get_deviceorientation_status: function(orientationState) { - if (!JsEvents.deviceOrientationEvent) { - return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; - } + if (!JSEvents.deviceOrientationEvent) return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; // HTML5 does not really have a polling API for device orientation events, so implement one manually by // returning the data from the most recently received event. This requires that user has registered // at least some no-op function as an event handler. - HEAP32.set(HEAP32.subarray(JsEvents.deviceOrientationEvent, {{{ C_STRUCTS.emscripten_DeviceOrientationEvent.__size__ }}}), orientationState); + HEAP32.set(HEAP32.subarray(JSEvents.deviceOrientationEvent, {{{ C_STRUCTS.EmscriptenDeviceOrientationEvent.__size__ }}}), orientationState); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_devicemotion_callback: function(userData, useCapture, callbackfunc) { - JsEvents.registerDeviceMotionEventCallback(window, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_DEVICEMOTION') }}}, "devicemotion"); + JSEvents.registerDeviceMotionEventCallback(window, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_DEVICEMOTION') }}}, "devicemotion"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_get_devicemotion_status: function(motionState) { - if (!JsEvents.deviceMotionEvent) { - return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; - } + if (!JSEvents.deviceMotionEvent) return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; // HTML5 does not really have a polling API for device motion events, so implement one manually by // returning the data from the most recently received event. This requires that user has registered // at least some no-op function as an event handler. - HEAP32.set(HEAP32.subarray(JsEvents.deviceMotionEvent, {{{ C_STRUCTS.emscripten_DeviceMotionEvent.__size__ }}}), motionState); + HEAP32.set(HEAP32.subarray(JSEvents.deviceMotionEvent, {{{ C_STRUCTS.EmscriptenDeviceMotionEvent.__size__ }}}), motionState); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_orientationchange_callback: function(userData, useCapture, callbackfunc) { - if (!window.screen || !window.screen.addEventListener) { - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; - } - JsEvents.registerOrientationChangeEventCallback(window.screen, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_ORIENTATIONCHANGE') }}}, "orientationchange"); + if (!window.screen || !window.screen.addEventListener) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + JSEvents.registerOrientationChangeEventCallback(window.screen, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_ORIENTATIONCHANGE') }}}, "orientationchange"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_get_orientation_status: function(orientationChangeEvent) { - JsEvents.fillOrientationChangeEventData(orientationChangeEvent); + if (!JSEvents.screenOrientation() && typeof window.orientation === 'undefined') return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + JSEvents.fillOrientationChangeEventData(orientationChangeEvent); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, @@ -1012,48 +1009,57 @@ var LibraryJsEvents = { return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, - emscripten_set_fullscreenchange_callback: function(userData, useCapture, callbackfunc) { - JsEvents.registerFullscreenChangeEventCallback(userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FULLSCREENCHANGE') }}}, "fullscreenchange"); + emscripten_set_fullscreenchange_callback: function(target, userData, useCapture, callbackfunc) { + if (typeof JSEvents.fullscreenEnabled() === 'undefined') return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + if (!target) target = document; + else { + target = JSEvents.findEventTarget(target); + if (!target) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + } + JSEvents.registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FULLSCREENCHANGE') }}}, "fullscreenchange"); + JSEvents.registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FULLSCREENCHANGE') }}}, "mozfullscreenchange"); + JSEvents.registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FULLSCREENCHANGE') }}}, "webkitfullscreenchange"); + JSEvents.registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FULLSCREENCHANGE') }}}, "msfullscreenchange"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_get_fullscreen_status: function(fullscreenStatus) { - JsEvents.fillFullscreenChangeEventData(fullscreenStatus); + if (typeof JSEvents.fullscreenEnabled() === 'undefined') return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + JSEvents.fillFullscreenChangeEventData(fullscreenStatus); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, // https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Using_full_screen_mode emscripten_request_fullscreen: function(target, deferUntilInEventHandler) { - if (!target) { - target = '#canvas'; - } - target = JsEvents.findEventTarget(target); - if (!target) { + if (typeof JSEvents.fullscreenEnabled() === 'undefined') return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + if (!JSEvents.fullscreenEnabled()) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + if (!target) target = '#canvas'; + target = JSEvents.findEventTarget(target); + if (!target) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + + if (!target.requestFullscreen && !target.msRequestFullscreen && !target.mozRequestFullScreen && !target.mozRequestFullscreen && !target.webkitRequestFullscreen) { return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; } - if (!target.requestFullscreen && !target.msRequestFullscreen && !target.mozRequestFullScreen && !target.webkitRequestFullscreen) { - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; - } - - var canPerformRequests = JsEvents.canPerformEventHandlerRequests(); + var canPerformRequests = JSEvents.canPerformEventHandlerRequests(); // Queue this function call if we're not currently in an event handler and the user saw it appropriate to do so. if (!canPerformRequests) { if (deferUntilInEventHandler) { - JsEvents.deferCall(JsEvents.requestFullscreen, 1 /* priority over pointer lock */, [target]); + JSEvents.deferCall(JSEvents.requestFullscreen, 1 /* priority over pointer lock */, [target]); return {{{ cDefine('EMSCRIPTEN_RESULT_DEFERRED') }}}; } else { return {{{ cDefine('EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED') }}}; } } - return JsEvents.requestFullscreen(target); + return JSEvents.requestFullscreen(target); }, emscripten_exit_fullscreen: function() { + if (typeof JSEvents.fullscreenEnabled() === 'undefined') return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; // Make sure no queued up calls will fire after this. - JsEvents.removeDeferredCalls(JsEvents.requestFullscreen); + JSEvents.removeDeferredCalls(JSEvents.requestFullscreen); if (document.exitFullscreen) { document.exitFullscreen(); @@ -1069,46 +1075,56 @@ var LibraryJsEvents = { return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, - emscripten_set_pointerlockchange_callback: function(userData, useCapture, callbackfunc) { - JsEvents.registerPointerlockChangeEventCallback(document, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKCHANGE') }}}, "pointerlockchange"); + emscripten_set_pointerlockchange_callback: function(target, userData, useCapture, callbackfunc) { + if (!document.body.requestPointerLock && !document.body.mozRequestPointerLock && !document.body.webkitRequestPointerLock && !document.body.msRequestPointerLock) { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + if (!target) target = document; + else { + target = JSEvents.findEventTarget(target); + if (!target) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + } + JSEvents.registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKCHANGE') }}}, "pointerlockchange"); + JSEvents.registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKCHANGE') }}}, "mozpointerlockchange"); + JSEvents.registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKCHANGE') }}}, "webkitpointerlockchange"); + JSEvents.registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKCHANGE') }}}, "mspointerlockchange"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_get_pointerlock_status: function(pointerlockStatus) { - JsEvents.fillPointerlockChangeEventData(pointerlockStatus); + if (!document.body.requestPointerLock && !document.body.mozRequestPointerLock && !document.body.webkitRequestPointerLock && !document.body.msRequestPointerLock) { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + JSEvents.fillPointerlockChangeEventData(pointerlockStatus); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_request_pointerlock: function(target, deferUntilInEventHandler) { - if (!target) { - target = '#canvas'; - } - target = JsEvents.findEventTarget(target); - if (!target) { - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; - } + if (!target) target = '#canvas'; + target = JSEvents.findEventTarget(target); + if (!target) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; if (!target.requestPointerLock && !target.mozRequestPointerLock && !target.webkitRequestPointerLock && !target.msRequestPointerLock) { return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; } - var canPerformRequests = JsEvents.canPerformEventHandlerRequests(); + var canPerformRequests = JSEvents.canPerformEventHandlerRequests(); // Queue this function call if we're not currently in an event handler and the user saw it appropriate to do so. if (!canPerformRequests) { if (deferUntilInEventHandler) { - JsEvents.deferCall(JsEvents.requestPointerLock, 2 /* priority below fullscreen */, [target]); + JSEvents.deferCall(JSEvents.requestPointerLock, 2 /* priority below fullscreen */, [target]); return {{{ cDefine('EMSCRIPTEN_RESULT_DEFERRED') }}}; } else { return {{{ cDefine('EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED') }}}; } } - return JsEvents.requestPointerLock(target); + return JSEvents.requestPointerLock(target); }, emscripten_exit_pointerlock: function() { // Make sure no queued up calls will fire after this. - JsEvents.removeDeferredCalls(JsEvents.requestPointerLock); + JSEvents.removeDeferredCalls(JSEvents.requestPointerLock); if (document.exitPointerLock) { document.exitPointerLock(); @@ -1125,18 +1141,13 @@ var LibraryJsEvents = { }, emscripten_vibrate: function(msecs) { - if (!navigator.vibrate) { - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; - } - + if (!navigator.vibrate) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; navigator.vibrate(msecs); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_vibrate_pattern: function(msecsArray, numEntries) { - if (!navigator.vibrate) { - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; - } + if (!navigator.vibrate) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; var vibrateList = []; for(var i = 0; i < numEntries; ++i) { @@ -1148,94 +1159,99 @@ var LibraryJsEvents = { }, emscripten_set_visibilitychange_callback: function(userData, useCapture, callbackfunc) { - JsEvents.registerVisibilityChangeEventCallback(document, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_VISIBILITYCHANGE') }}}, "visibilitychange"); + JSEvents.registerVisibilityChangeEventCallback(document, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_VISIBILITYCHANGE') }}}, "visibilitychange"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_get_visibility_status: function(visibilityStatus) { - JsEvents.fillVisibilityChangeEventData(visibilityStatus); + if (typeof document.visibilityState === 'undefined' && typeof document.hidden === 'undefined') { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + JSEvents.fillVisibilityChangeEventData(visibilityStatus); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_touchstart_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHSTART') }}}, "touchstart"); + JSEvents.registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHSTART') }}}, "touchstart"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_touchend_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHEND') }}}, "touchend"); + JSEvents.registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHEND') }}}, "touchend"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_touchmove_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHMOVE') }}}, "touchmove"); + JSEvents.registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHMOVE') }}}, "touchmove"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_touchcancel_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHCANCEL') }}}, "touchcancel"); + JSEvents.registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHCANCEL') }}}, "touchcancel"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_gamepadconnected_callback: function(userData, useCapture, callbackfunc) { - JsEvents.registerGamepadEventCallback(window, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_GAMEPADCONNECTED') }}}, "gamepadconnected"); + if (!navigator.getGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + JSEvents.registerGamepadEventCallback(window, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_GAMEPADCONNECTED') }}}, "gamepadconnected"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_gamepaddisconnected_callback: function(userData, useCapture, callbackfunc) { - JsEvents.registerGamepadEventCallback(window, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED') }}}, "gamepaddisconnected"); + if (!navigator.getGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + JSEvents.registerGamepadEventCallback(window, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED') }}}, "gamepaddisconnected"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_get_num_gamepads: function() { - if (!navigator.getGamepads) { - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; - } + if (!navigator.getGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; return navigator.getGamepads().length; }, emscripten_get_gamepad_status: function(index, gamepadState) { - if (!navigator.getGamepads) { - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; - } + if (!navigator.getGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; var gamepads = navigator.getGamepads(); if (index < 0 || index >= gamepads.length) { return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; } - JsEvents.fillGamepadEventData(gamepadState, gamepads[index]); + JSEvents.fillGamepadEventData(gamepadState, gamepads[index]); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_beforeunload_callback: function(userData, callbackfunc) { - JsEvents.registerBeforeUnloadEventCallback(window, userData, true, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BEFOREUNLOAD') }}}, "beforeunload"); + if (typeof window.onbeforeunload === 'undefined') return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + JSEvents.registerBeforeUnloadEventCallback(window, userData, true, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BEFOREUNLOAD') }}}, "beforeunload"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_batterychargingchange_callback: function(userData, callbackfunc) { - JsEvents.registerBatteryEventCallback(JsEvents.battery(), userData, true, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE') }}}, "chargingchange"); + if (!JSEvents.battery()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + JSEvents.registerBatteryEventCallback(JSEvents.battery(), userData, true, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE') }}}, "chargingchange"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_batterylevelchange_callback: function(userData, callbackfunc) { - JsEvents.registerBatteryEventCallback(JsEvents.battery(), userData, true, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE') }}}, "levelchange"); + if (!JSEvents.battery()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + JSEvents.registerBatteryEventCallback(JSEvents.battery(), userData, true, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE') }}}, "levelchange"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_get_battery_status: function(batteryState) { - JsEvents.fillBatteryEventData(batteryState, JsEvents.battery()); + if (!JSEvents.battery()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + JSEvents.fillBatteryEventData(batteryState, JSEvents.battery()); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_webglcontextlost_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST') }}}, "webglcontextlost"); + JSEvents.registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST') }}}, "webglcontextlost"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_webglcontextrestored_callback: function(target, userData, useCapture, callbackfunc) { - JsEvents.registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED') }}}, "webglcontextrestored"); + JSEvents.registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED') }}}, "webglcontextrestored"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, }; -autoAddDeps(LibraryJsEvents, '$JsEvents'); -mergeInto(LibraryManager.library, LibraryJsEvents); +autoAddDeps(LibraryJSEvents, '$JSEvents'); +mergeInto(LibraryManager.library, LibraryJSEvents); diff --git a/src/modules.js b/src/modules.js index 7b267971f..ea1509e9d 100644 --- a/src/modules.js +++ b/src/modules.js @@ -424,7 +424,7 @@ var LibraryManager = { load: function() { if (this.library) return; - var libraries = ['library.js', 'library_path.js', 'library_fs.js', 'library_idbfs.js', 'library_memfs.js', 'library_nodefs.js', 'library_sockfs.js', 'library_tty.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js', 'library_uuid.js', 'library_glew.js', 'library_events.js'].concat(additionalLibraries); + var libraries = ['library.js', 'library_path.js', 'library_fs.js', 'library_idbfs.js', 'library_memfs.js', 'library_nodefs.js', 'library_sockfs.js', 'library_tty.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js', 'library_uuid.js', 'library_glew.js', 'library_html5.js'].concat(additionalLibraries); for (var i = 0; i < libraries.length; i++) { eval(processMacros(preprocess(read(libraries[i])))); } diff --git a/src/struct_info.json b/src/struct_info.json index ec4490974..32261c0a7 100644 --- a/src/struct_info.json +++ b/src/struct_info.json @@ -1075,10 +1075,10 @@ "structs": {} }, // =========================================== - // emscripten events library + // emscripten html5 library // =========================================== { - "file": "emscripten/events.h", + "file": "emscripten/html5.h", "defines": [ "EMSCRIPTEN_EVENT_KEYPRESS", "EMSCRIPTEN_EVENT_KEYDOWN", @@ -1117,13 +1117,14 @@ "EMSCRIPTEN_RESULT_DEFERRED", "EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED", "EMSCRIPTEN_RESULT_INVALID_TARGET", + "EMSCRIPTEN_RESULT_UNKNOWN_TARGET", "EMSCRIPTEN_RESULT_INVALID_PARAM", "EMSCRIPTEN_RESULT_NOT_SUPPORTED", "EMSCRIPTEN_RESULT_FAILED", "EMSCRIPTEN_RESULT_NO_DATA" ], "structs": { - "emscripten_KeyboardEvent": [ + "EmscriptenKeyboardEvent": [ "key", "code", "location", @@ -1138,7 +1139,7 @@ "keyCode", "which" ], - "emscripten_MouseEvent": [ + "EmscriptenMouseEvent": [ "timestamp", "screenX", "screenY", @@ -1155,14 +1156,14 @@ "canvasX", "canvasY" ], - "emscripten_WheelEvent": [ + "EmscriptenWheelEvent": [ "mouse", "deltaX", "deltaY", "deltaZ", "deltaMode" ], - "emscripten_UiEvent": [ + "EmscriptenUiEvent": [ "detail", "documentBodyClientWidth", "documentBodyClientHeight", @@ -1173,18 +1174,18 @@ "scrollTop", "scrollLeft" ], - "emscripten_FocusEvent": [ + "EmscriptenFocusEvent": [ "nodeName", "id" ], - "emscripten_DeviceOrientationEvent": [ + "EmscriptenDeviceOrientationEvent": [ "timestamp", "alpha", "beta", "gamma", "absolute" ], - "emscripten_DeviceMotionEvent": [ + "EmscriptenDeviceMotionEvent": [ "timestamp", "accelerationX", "accelerationY", @@ -1196,26 +1197,26 @@ "rotationRateBeta", "rotationRateGamma" ], - "emscripten_OrientationChangeEvent": [ + "EmscriptenOrientationChangeEvent": [ "orientationIndex", "orientationAngle" ], - "emscripten_FullscreenChangeEvent": [ + "EmscriptenFullscreenChangeEvent": [ "isFullscreen", "fullscreenEnabled", "nodeName", "id" ], - "emscripten_PointerlockChangeEvent": [ + "EmscriptenPointerlockChangeEvent": [ "isActive", "nodeName", "id" ], - "emscripten_VisibilityChangeEvent": [ + "EmscriptenVisibilityChangeEvent": [ "hidden", "visibilityState" ], - "emscripten_TouchPoint": [ + "EmscriptenTouchPoint": [ "identifier", "screenX", "screenY", @@ -1228,7 +1229,7 @@ "canvasX", "canvasY" ], - "emscripten_TouchEvent": [ + "EmscriptenTouchEvent": [ "numTouches", "ctrlKey", "shiftKey", @@ -1236,7 +1237,7 @@ "metaKey", "touches" ], - "emscripten_GamepadEvent": [ + "EmscriptenGamepadEvent": [ "timestamp", "axis", "analogButton", @@ -1248,7 +1249,7 @@ "id", "mapping" ], - "emscripten_BatteryEvent": [ + "EmscriptenBatteryEvent": [ "chargingTime", "dischargingTime", "level", diff --git a/system/include/emscripten/events.h b/system/include/emscripten/html5.h similarity index 86% rename from system/include/emscripten/events.h rename to system/include/emscripten/html5.h index 4caae3cfd..06c647bfd 100644 --- a/system/include/emscripten/events.h +++ b/system/include/emscripten/html5.h @@ -99,14 +99,17 @@ extern "C" { // The given target element for the operation is invalid. #define EMSCRIPTEN_RESULT_INVALID_TARGET -3 +// The given target element for the operation was not found. +#define EMSCRIPTEN_RESULT_UNKNOWN_TARGET -4 + // An invalid parameter was passed to the function. -#define EMSCRIPTEN_RESULT_INVALID_PARAM -4 +#define EMSCRIPTEN_RESULT_INVALID_PARAM -5 // The operation failed due to some generic reason. -#define EMSCRIPTEN_RESULT_FAILED -5 +#define EMSCRIPTEN_RESULT_FAILED -6 // Operation failed since no data is currently available. -#define EMSCRIPTEN_RESULT_NO_DATA -6 +#define EMSCRIPTEN_RESULT_NO_DATA -7 #define EM_BOOL int #define EM_UTF8 char @@ -121,7 +124,7 @@ extern "C" { * The event structure passed in keyboard events keypress, keydown and keyup. * https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#keys */ -typedef struct emscripten_KeyboardEvent { +typedef struct EmscriptenKeyboardEvent { // The printed representation of the pressed key. EM_UTF8 key[32]; // A string that identifies the physical key being pressed. The value is not affected by the current keyboard @@ -150,22 +153,22 @@ typedef struct emscripten_KeyboardEvent { unsigned long keyCode; // A system and implementation dependent numeric code identifying the unmodified value of the pressed key; this is usually the same as keyCode. unsigned long which; -} emscripten_KeyboardEvent; +} EmscriptenKeyboardEvent; /* * Registers a callback function for receiving browser-generated keyboard input events. * See https://developer.mozilla.org/en/DOM/Event/UIEvent/KeyEvent * and http://www.javascriptkit.com/jsref/eventkeyboardmouse.shtml */ -extern EMSCRIPTEN_RESULT emscripten_set_keypress_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const emscripten_KeyboardEvent *keyEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_keydown_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const emscripten_KeyboardEvent *keyEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_keyup_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const emscripten_KeyboardEvent *keyEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_keypress_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_keydown_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_keyup_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)); /* * The event structure passed in mouse events click, mousedown, mouseup, dblclick and mousemove. * https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#interface-MouseEvent */ -typedef struct emscripten_MouseEvent { +typedef struct EmscriptenMouseEvent { // A timestamp of when this data was generated by the browser. This is an absolute wallclock time in milliseconds. double timestamp; // The coordinate relative to the browser screen coordinate system. @@ -191,22 +194,22 @@ typedef struct emscripten_MouseEvent { long canvasY; // Pad this struct to multiple of 8 bytes to make WheelEvent unambiguously align to 8 bytes. long padding; -} emscripten_MouseEvent; +} EmscriptenMouseEvent; /* * Registers a callback function for receiving browser-generated mouse input events. * See https://developer.mozilla.org/en/DOM/MouseEvent */ -extern EMSCRIPTEN_RESULT emscripten_set_click_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const emscripten_MouseEvent *mouseEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_mousedown_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const emscripten_MouseEvent *mouseEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_mouseup_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const emscripten_MouseEvent *mouseEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_dblclick_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const emscripten_MouseEvent *mouseEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_mousemove_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const emscripten_MouseEvent *mouseEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_click_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_mousedown_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_mouseup_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_dblclick_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_mousemove_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)); /* * Returns the most recently received mouse event state. Note that for this function call to succeed, emscripten_set_xx_callback must have first * been called with one of the mouse event types and a non-zero callback function pointer to enable the Mouse state capture. */ -extern EMSCRIPTEN_RESULT emscripten_get_mouse_status(emscripten_MouseEvent *mouseState); +extern EMSCRIPTEN_RESULT emscripten_get_mouse_status(EmscriptenMouseEvent *mouseState); #define DOM_DELTA_PIXEL 0x00 #define DOM_DELTA_LINE 0x01 @@ -216,28 +219,28 @@ extern EMSCRIPTEN_RESULT emscripten_get_mouse_status(emscripten_MouseEvent *mous * The event structure passed in mouse wheelevent. * https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#interface-WheelEvent */ -typedef struct emscripten_WheelEvent { +typedef struct EmscriptenWheelEvent { // Specifies general mouse information related to this event. - emscripten_MouseEvent mouse; + EmscriptenMouseEvent mouse; // Measures along different axes the movement of the wheel. double deltaX; double deltaY; double deltaZ; // One of the DOM_DELTA_ values that indicates the units of measurement for the delta values. unsigned long deltaMode; -} emscripten_WheelEvent; +} EmscriptenWheelEvent; /* * Registers a callback function for receiving browser-generated mouse wheel events. * See http://www.w3.org/TR/DOM-Level-3-Events/#event-type-wheel */ -extern EMSCRIPTEN_RESULT emscripten_set_wheel_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_WheelEvent *wheelEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_wheel_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData)); /* * The event structure passed in DOM element resize and scroll events. * https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#interface-UIEvent */ -typedef struct emscripten_UiEvent { +typedef struct EmscriptenUiEvent { // Specifies detail information about this event. long detail; // The clientWidth/clientHeight of the document.body element. @@ -252,40 +255,40 @@ typedef struct emscripten_UiEvent { // The page scroll position. int scrollTop; int scrollLeft; -} emscripten_UiEvent; +} EmscriptenUiEvent; /* * Registers a callback function for receiving DOM element resize and scroll events. * See https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#event-type-resize */ -extern EMSCRIPTEN_RESULT emscripten_set_resize_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_UiEvent *uiEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_scroll_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_UiEvent *uiEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_resize_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenUiEvent *uiEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_scroll_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenUiEvent *uiEvent, void *userData)); /* * The event structure passed in DOM element blur, focus, focusin and focusout events. * https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#interface-FocusEvent */ -typedef struct emscripten_FocusEvent { +typedef struct EmscriptenFocusEvent { // The nodeName of the target HTML Element. See https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeName EM_UTF8 nodeName[128]; // The HTML Element ID of the target element. EM_UTF8 id[128]; -} emscripten_FocusEvent; +} EmscriptenFocusEvent; /* * Registers a callback function for receiving DOM element blur, focus, focusin and focusout events. * See https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#event-type-blur */ -extern EMSCRIPTEN_RESULT emscripten_set_blur_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_FocusEvent *focusEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_focus_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_FocusEvent *focusEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_focusin_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_FocusEvent *focusEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_focusout_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_FocusEvent *focusEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_blur_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_focus_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_focusin_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_focusout_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)); /* * The event structure passed in the deviceorientation event. * http://dev.w3.org/geo/api/spec-source-orientation.html#deviceorientation */ -typedef struct emscripten_DeviceOrientationEvent { +typedef struct EmscriptenDeviceOrientationEvent { // Absolute wallclock time in msec units of when the event occurred. double timestamp; // The orientation of the device in terms of the transformation from a coordinate frame fixed on the Earth to a coordinate frame fixed in the device. @@ -294,24 +297,24 @@ typedef struct emscripten_DeviceOrientationEvent { double gamma; // If false, the orientation is only relative to some other bas orinetation, not to the fixed coordinate frame. EM_BOOL absolute; -} emscripten_DeviceOrientationEvent; +} EmscriptenDeviceOrientationEvent; /* * Registers a callback function for receiving the deviceorientation event. * See http://dev.w3.org/geo/api/spec-source-orientation.html */ -extern EMSCRIPTEN_RESULT emscripten_set_deviceorientation_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_DeviceOrientationEvent *orientationEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_deviceorientation_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenDeviceOrientationEvent *orientationEvent, void *userData)); /* * Returns the most recently received deviceorientation event state. Note that for this function call to succeed, emscripten_set_deviceorientation_callback * must have first been called with one of the mouse event types and a non-zero callback function pointer to enable the Device Orientation state capture. */ -extern EMSCRIPTEN_RESULT emscripten_get_deviceorientation_status(emscripten_DeviceOrientationEvent *orientationState); +extern EMSCRIPTEN_RESULT emscripten_get_deviceorientation_status(EmscriptenDeviceOrientationEvent *orientationState); /* * The event structure passed in the devicemotion event. * http://dev.w3.org/geo/api/spec-source-orientation.html#devicemotion */ -typedef struct emscripten_DeviceMotionEvent { +typedef struct EmscriptenDeviceMotionEvent { // Absolute wallclock time in msec units of when the event occurred. double timestamp; // Acceleration of the device excluding gravity. @@ -326,18 +329,18 @@ typedef struct emscripten_DeviceMotionEvent { double rotationRateAlpha; double rotationRateBeta; double rotationRateGamma; -} emscripten_DeviceMotionEvent; +} EmscriptenDeviceMotionEvent; /* * Registers a callback function for receiving the devicemotion event. * See http://dev.w3.org/geo/api/spec-source-orientation.html */ -extern EMSCRIPTEN_RESULT emscripten_set_devicemotion_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_DeviceMotionEvent *motionEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_devicemotion_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenDeviceMotionEvent *motionEvent, void *userData)); /* * Returns the most recently received deviceomotion event state. Note that for this function call to succeed, emscripten_set_devicemotion_callback * must have first been called with one of the mouse event types and a non-zero callback function pointer to enable the Device Motion state capture. */ -extern EMSCRIPTEN_RESULT emscripten_get_devicemotion_status(emscripten_DeviceMotionEvent *motionState); +extern EMSCRIPTEN_RESULT emscripten_get_devicemotion_status(EmscriptenDeviceMotionEvent *motionState); #define EMSCRIPTEN_ORIENTATION_PORTRAIT_PRIMARY 1 #define EMSCRIPTEN_ORIENTATION_PORTRAIT_SECONDARY 2 @@ -348,23 +351,23 @@ extern EMSCRIPTEN_RESULT emscripten_get_devicemotion_status(emscripten_DeviceMot * The event structure passed in the orientationchange event. * https://dvcs.w3.org/hg/screen-orientation/raw-file/tip/Overview.html */ -typedef struct emscripten_OrientationChangeEvent { +typedef struct EmscriptenOrientationChangeEvent { // One of EM_ORIENTATION_PORTRAIT_xx fields, or -1 if unknown. int orientationIndex; // Emscripten-specific extension: Some browsers refer to 'window.orientation', so report that as well. // Orientation angle in degrees. 0: "default orientation", i.e. default upright orientation to hold the mobile device in. Could be either landscape or portrait. int orientationAngle; -} emscripten_OrientationChangeEvent; +} EmscriptenOrientationChangeEvent; /* * Registers a callback function for receiving the orientationchange event. * https://dvcs.w3.org/hg/screen-orientation/raw-file/tip/Overview.html */ -extern EMSCRIPTEN_RESULT emscripten_set_orientationchange_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_OrientationChangeEvent *orientationChangeEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_orientationchange_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenOrientationChangeEvent *orientationChangeEvent, void *userData)); /* * Returns the current device orientation state. */ -extern EMSCRIPTEN_RESULT emscripten_get_orientation_status(emscripten_OrientationChangeEvent *orientationStatus); +extern EMSCRIPTEN_RESULT emscripten_get_orientation_status(EmscriptenOrientationChangeEvent *orientationStatus); /* * Locks the screen orientation to the given set of allowed orientations. * allowedOrientations: A bitfield set of EM_ORIENTATION_xx flags. @@ -379,7 +382,7 @@ extern EMSCRIPTEN_RESULT emscripten_unlock_orientation(); * The event structure passed in the fullscreenchange event. * https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html */ -typedef struct emscripten_FullscreenChangeEvent { +typedef struct EmscriptenFullscreenChangeEvent { // Specifies whether an element on the browser page is currently fullscreen. EM_BOOL isFullscreen; // Specifies if the current page has the ability to display elements fullscreen. @@ -388,17 +391,17 @@ typedef struct emscripten_FullscreenChangeEvent { EM_UTF8 nodeName[128]; // The HTML Element ID of the target HTML element that is in full screen mode. EM_UTF8 id[128]; -} emscripten_FullscreenChangeEvent; +} EmscriptenFullscreenChangeEvent; /* * Registers a callback function for receiving the fullscreenchange event. * https://dvcs.w3.org/hg/screen-orientation/raw-file/tip/Overview.html */ -extern EMSCRIPTEN_RESULT emscripten_set_fullscreenchange_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_FullscreenChangeEvent *fullscreenChangeEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_fullscreenchange_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent, void *userData)); /* * Returns the current page fullscreen state. */ -extern EMSCRIPTEN_RESULT emscripten_get_fullscreen_status(emscripten_FullscreenChangeEvent *fullscreenStatus); +extern EMSCRIPTEN_RESULT emscripten_get_fullscreen_status(EmscriptenFullscreenChangeEvent *fullscreenStatus); /* * Requests the given target element to transition to full screen mode. * Note: This function can only run inside a user-generated JavaScript event handler. @@ -416,25 +419,25 @@ extern EMSCRIPTEN_RESULT emscripten_exit_fullscreen(); * The event structure passed in the pointerlockchange event. * http://www.w3.org/TR/pointerlock/ */ -typedef struct emscripten_PointerlockChangeEvent { +typedef struct EmscriptenPointerlockChangeEvent { // Specifies whether an element on the browser page currently has pointer lock enabled. EM_BOOL isActive; // The nodeName of the target HTML Element that has the pointer lock active. See https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeName EM_UTF8 nodeName[128]; // The HTML Element ID of the target HTML element that has the pointer lock active. EM_UTF8 id[128]; -} emscripten_PointerlockChangeEvent; +} EmscriptenPointerlockChangeEvent; /* * Registers a callback function for receiving the pointerlockchange event. * Pointer lock hides the mouse cursor and exclusively gives the target element relative mouse movement events via the mousemove event. * http://www.w3.org/TR/pointerlock/ */ -extern EMSCRIPTEN_RESULT emscripten_set_pointerlockchange_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_PointerlockChangeEvent *pointerlockChangeEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_pointerlockchange_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenPointerlockChangeEvent *pointerlockChangeEvent, void *userData)); /* * Returns the current page pointerlock state. */ -extern EMSCRIPTEN_RESULT emscripten_get_pointerlock_status(emscripten_PointerlockChangeEvent *pointerlockStatus); +extern EMSCRIPTEN_RESULT emscripten_get_pointerlock_status(EmscriptenPointerlockChangeEvent *pointerlockStatus); /* * Requests the given target element to grab pointerlock. * Note: This function can only run inside a user-generated JavaScript event handler. @@ -457,28 +460,28 @@ extern EMSCRIPTEN_RESULT emscripten_exit_pointerlock(); * The event structure passed in the visibilitychange event. * http://www.w3c-test.org/webperf/specs/PageVisibility/ */ -typedef struct emscripten_VisibilityChangeEvent { +typedef struct EmscriptenVisibilityChangeEvent { // If true, the current browser page is now hidden. EM_BOOL hidden; // Specifies a more fine-grained state of the current page visibility status. One of the EMSCRIPTEN_VISIBILITY_ values. int visibilityState; -} emscripten_VisibilityChangeEvent; +} EmscriptenVisibilityChangeEvent; /* * Registers a callback function for receiving the visibilitychange event. * http://www.w3c-test.org/webperf/specs/PageVisibility/ */ -extern EMSCRIPTEN_RESULT emscripten_set_visibilitychange_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_VisibilityChangeEvent *visibilityChangeEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_visibilitychange_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenVisibilityChangeEvent *visibilityChangeEvent, void *userData)); /* * Returns the current page visibility state. */ -extern EMSCRIPTEN_RESULT emscripten_get_visibility_status(emscripten_VisibilityChangeEvent *visibilityStatus); +extern EMSCRIPTEN_RESULT emscripten_get_visibility_status(EmscriptenVisibilityChangeEvent *visibilityStatus); /* * Specifies the status of a single touch point on the page. * See http://www.w3.org/TR/touch-events/#touch-interface */ -typedef struct emscripten_TouchPoint +typedef struct EmscriptenTouchPoint { // An identification number for each touch point. long identifier; @@ -498,13 +501,13 @@ typedef struct emscripten_TouchPoint // The touch coordinates mapped to the Emscripten canvas client area, in pixels. long canvasX; long canvasY; -} emscripten_TouchPoint; +} EmscriptenTouchPoint; /* * Specifies the data of a single touch event. * See http://www.w3.org/TR/touch-events/#touchevent-interface */ -typedef struct emscripten_TouchEvent { +typedef struct EmscriptenTouchEvent { // The number of valid elements in the touches array. int numTouches; // Specifies which modifiers were active during the key event. @@ -513,23 +516,23 @@ typedef struct emscripten_TouchEvent { EM_BOOL altKey; EM_BOOL metaKey; // An array of currently active touches, one for each finger. - emscripten_TouchPoint touches[32]; -} emscripten_TouchEvent; + EmscriptenTouchPoint touches[32]; +} EmscriptenTouchEvent; /* * Registers a callback function for receiving the touchstart, touchend, touchmove and touchcancel events. * http://www.w3.org/TR/touch-events/ */ -extern EMSCRIPTEN_RESULT emscripten_set_touchstart_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_TouchEvent *touchEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_touchend_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_TouchEvent *touchEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_touchmove_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_TouchEvent *touchEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_touchcancel_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_TouchEvent *touchEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_touchstart_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_touchend_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_touchmove_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_touchcancel_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)); /* * Represents the current snapshot state of a gamepad. * http://www.w3.org/TR/gamepad/#gamepad-interface */ -typedef struct emscripten_GamepadEvent { +typedef struct EmscriptenGamepadEvent { // Absolute wallclock time in msec units of when the data was recorded. double timestamp; // The number of valid axes entries in the axis array. @@ -550,14 +553,14 @@ typedef struct emscripten_GamepadEvent { EM_UTF8 id[64]; // A string that identifies the layout or control mapping of this device. EM_UTF8 mapping[64]; -} emscripten_GamepadEvent; +} EmscriptenGamepadEvent; /* * Registers a callback function for receiving the gamepadconnected and gamepaddisconnected events. * http://www.w3.org/TR/gamepad/ */ -extern EMSCRIPTEN_RESULT emscripten_set_gamepadconnected_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_GamepadEvent *gamepadEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_gamepaddisconnected_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const emscripten_GamepadEvent *gamepadEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_gamepadconnected_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_gamepaddisconnected_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)); /* * Returns the number of gamepads connected to the system or EMSCRIPTEN_RESULT_NOT_SUPPORTED if the current browser does not support gamepads. @@ -567,29 +570,29 @@ extern int emscripten_get_num_gamepads(); /* * Returns a snapshot of the current gamepad state. */ -extern EMSCRIPTEN_RESULT emscripten_get_gamepad_status(int index, emscripten_GamepadEvent *gamepadState); +extern EMSCRIPTEN_RESULT emscripten_get_gamepad_status(int index, EmscriptenGamepadEvent *gamepadState); /* * The event structure passed in the battery chargingchange and levelchange event. * http://www.w3.org/TR/battery-status/#batterymanager-interface */ -typedef struct emscripten_BatteryEvent { +typedef struct EmscriptenBatteryEvent { double chargingTime; double dischargingTime; double level; EM_BOOL charging; -} emscripten_BatteryEvent; +} EmscriptenBatteryEvent; /* * Registers a callback function for receiving the battery chargingchange and levelchange events. * http://www.w3.org/TR/battery-status/ */ -extern EMSCRIPTEN_RESULT emscripten_set_batterychargingchange_callback(void *userData, EM_BOOL (*func)(int eventType, const emscripten_BatteryEvent *batteryEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_batterylevelchange_callback(void *userData, EM_BOOL (*func)(int eventType, const emscripten_BatteryEvent *batteryEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_batterychargingchange_callback(void *userData, EM_BOOL (*func)(int eventType, const EmscriptenBatteryEvent *batteryEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_batterylevelchange_callback(void *userData, EM_BOOL (*func)(int eventType, const EmscriptenBatteryEvent *batteryEvent, void *userData)); /* * Returns the current battery status. */ -extern EMSCRIPTEN_RESULT emscripten_get_battery_status(emscripten_BatteryEvent *batteryState); +extern EMSCRIPTEN_RESULT emscripten_get_battery_status(EmscriptenBatteryEvent *batteryState); /* * Produces a vibration feedback for given msecs. diff --git a/tests/test_browser.py b/tests/test_browser.py index e7139f6ef..226eddee3 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -1768,5 +1768,5 @@ Module["preRun"].push(function () { self.btest('doublestart.c', args=['--pre-js', 'pre.js', '-o', 'test.html'], expected='1') - def test_events(self): - self.btest(path_from_root('tests', 'test_events.c'), expected='0') + def test_html5(self): + self.btest(path_from_root('tests', 'test_html5.c'), expected='0') diff --git a/tests/test_events.c b/tests/test_events.c deleted file mode 100644 index 23fa87045..000000000 --- a/tests/test_events.c +++ /dev/null @@ -1,382 +0,0 @@ -#include -#include -#include -#include - -static inline const char *emscripten_event_type_to_string(int eventType) { - const char *events[] = { "(invalid)", "(none)", "keypress", "keydown", "keyup", "click", "mousedown", "mouseup", "dblclick", "mousemove", "wheel", "resize", - "scroll", "blur", "focus", "focusin", "focusout", "deviceorientation", "devicemotion", "orientationchange", "fullscreenchange", "pointerlockchange", - "visibilitychange", "touchstart", "touchend", "touchmove", "touchcancel", "gamepadconnected", "gamepaddisconnected", "beforeunload", - "batterychargingchange", "batterylevelchange", "webglcontextlost", "webglcontextrestored", "(invalid)" }; - ++eventType; - if (eventType < 0) eventType = 0; - if (eventType >= sizeof(events)/sizeof(events[0])) eventType = sizeof(events)/sizeof(events[0])-1; - return events[eventType]; -} - -// The event handler functions can return 1 to suppress the event and disable the default action. That calls event.preventDefault(); -// Returning 0 signals that the event was not consumed by the code, and will allow the event to pass on and bubble up normally. -EM_BOOL key_callback(int eventType, const emscripten_KeyboardEvent *e, void *userData) -{ - printf("%s, key: \"%s\", code: \"%s\", location: %lu,%s%s%s%s repeat: %d, locale: \"%s\", char: \"%s\", charCode: %lu, keyCode: %lu, which: %lu\n", - emscripten_event_type_to_string(eventType), e->key, e->code, e->location, - e->ctrlKey ? " CTRL" : "", e->shiftKey ? " SHIFT" : "", e->altKey ? " ALT" : "", e->metaKey ? " META" : "", - e->repeat, e->locale, e->charValue, e->charCode, e->keyCode, e->which); - - if (eventType == EMSCRIPTEN_EVENT_KEYPRESS && !strcmp(e->key, "f")) { - emscripten_FullscreenChangeEvent fsce; - emscripten_get_fullscreen_status(&fsce); - if (!fsce.isFullscreen) { - emscripten_request_fullscreen(0, 1); - } else { - emscripten_exit_fullscreen(); - } - } - - if (eventType == EMSCRIPTEN_EVENT_KEYPRESS && !strcmp(e->key, "p")) { - emscripten_PointerlockChangeEvent plce; - emscripten_get_pointerlock_status(&plce); - if (!plce.isActive) { - emscripten_request_pointerlock(0, 1); - } else { - emscripten_exit_pointerlock(); - } - } - - return 0; -} - -EM_BOOL mouse_callback(int eventType, const emscripten_MouseEvent *e, void *userData) -{ - printf("%s, screen: (%ld,%ld), client: (%ld,%ld),%s%s%s%s button: %hu, buttons: %hu, movement: (%ld,%ld), canvas: (%ld,%ld)\n", - emscripten_event_type_to_string(eventType), e->screenX, e->screenY, e->clientX, e->clientY, - e->ctrlKey ? " CTRL" : "", e->shiftKey ? " SHIFT" : "", e->altKey ? " ALT" : "", e->metaKey ? " META" : "", - e->button, e->buttons, e->movementX, e->movementY, e->canvasX, e->canvasY); - - return 0; -} - -EM_BOOL wheel_callback(int eventType, const emscripten_WheelEvent *e, void *userData) -{ - printf("%s, screen: (%ld,%ld), client: (%ld,%ld),%s%s%s%s button: %hu, buttons: %hu, canvas: (%ld,%ld), delta:(%g,%g,%g), deltaMode:%lu\n", - emscripten_event_type_to_string(eventType), e->mouse.screenX, e->mouse.screenY, e->mouse.clientX, e->mouse.clientY, - e->mouse.ctrlKey ? " CTRL" : "", e->mouse.shiftKey ? " SHIFT" : "", e->mouse.altKey ? " ALT" : "", e->mouse.metaKey ? " META" : "", - e->mouse.button, e->mouse.buttons, e->mouse.canvasX, e->mouse.canvasY, - (float)e->deltaX, (float)e->deltaY, (float)e->deltaZ, e->deltaMode); - - return 0; -} - -EM_BOOL uievent_callback(int eventType, const emscripten_UiEvent *e, void *userData) -{ - printf("%s, detail: %ld, document.body.client size: (%d,%d), window.inner size: (%d,%d), scrollPos: (%d, %d)\n", - emscripten_event_type_to_string(eventType), e->detail, e->documentBodyClientWidth, e->documentBodyClientHeight, - e->windowInnerWidth, e->windowInnerHeight, e->scrollTop, e->scrollLeft); - - return 0; -} - -EM_BOOL focusevent_callback(int eventType, const emscripten_FocusEvent *e, void *userData) -{ - printf("%s, nodeName: \"%s\", id: \"%s\"\n", emscripten_event_type_to_string(eventType), e->nodeName, e->id[0] == '\0' ? "(empty string)" : e->id); - - return 0; -} - -EM_BOOL deviceorientation_callback(int eventType, const emscripten_DeviceOrientationEvent *e, void *userData) -{ - printf("%s, (%g, %g, %g)\n", emscripten_event_type_to_string(eventType), e->alpha, e->beta, e->gamma); - - return 0; -} - -EM_BOOL devicemotion_callback(int eventType, const emscripten_DeviceMotionEvent *e, void *userData) -{ - printf("%s, accel: (%g, %g, %g), accelInclGravity: (%g, %g, %g), rotationRate: (%g, %g, %g)\n", - emscripten_event_type_to_string(eventType), - e->accelerationX, e->accelerationY, e->accelerationZ, - e->accelerationIncludingGravityX, e->accelerationIncludingGravityY, e->accelerationIncludingGravityZ, - e->rotationRateAlpha, e->rotationRateBeta, e->rotationRateGamma); - - return 0; -} - -EM_BOOL orientationchange_callback(int eventType, const emscripten_OrientationChangeEvent *e, void *userData) -{ - printf("%s, orientationAngle: %d, orientationIndex: %d\n", emscripten_event_type_to_string(eventType), e->orientationAngle, e->orientationIndex); - - return 0; -} - -EM_BOOL fullscreenchange_callback(int eventType, const emscripten_FullscreenChangeEvent *e, void *userData) -{ - printf("%s, isFullscreen: %d, fullscreenEnabled: %d, fs element nodeName: \"%s\", fs element id: \"%s\"\n", - emscripten_event_type_to_string(eventType), e->isFullscreen, e->fullscreenEnabled, e->nodeName, e->id); - - return 0; -} - -EM_BOOL pointerlockchange_callback(int eventType, const emscripten_PointerlockChangeEvent *e, void *userData) -{ - printf("%s, isActive: %d, pointerlock element nodeName: \"%s\", id: \"%s\"\n", - emscripten_event_type_to_string(eventType), e->isActive, e->nodeName, e->id); - - return 0; -} - -EM_BOOL visibilitychange_callback(int eventType, const emscripten_VisibilityChangeEvent *e, void *userData) -{ - printf("%s, hidden: %d, visibilityState: %d\n", emscripten_event_type_to_string(eventType), e->hidden, e->visibilityState); - - return 0; -} - -EM_BOOL touch_callback(int eventType, const emscripten_TouchEvent *e, void *userData) -{ - printf("%s, numTouches: %d %s%s%s%s\n", - emscripten_event_type_to_string(eventType), e->numTouches, - e->ctrlKey ? " CTRL" : "", e->shiftKey ? " SHIFT" : "", e->altKey ? " ALT" : "", e->metaKey ? " META" : ""); - for(int i = 0; i < e->numTouches; ++i) - { - const emscripten_TouchPoint *t = &e->touches[i]; - printf(" %ld: screen: (%ld,%ld), client: (%ld,%ld), page: (%ld,%ld), isChanged: %d, onTarget: %d, canvas: (%ld, %ld)\n", - t->identifier, t->screenX, t->screenY, t->clientX, t->clientY, t->pageX, t->pageY, t->isChanged, t->onTarget, t->canvasX, t->canvasY); - } - - return 0; -} - -EM_BOOL gamepad_callback(int eventType, const emscripten_GamepadEvent *e, void *userData) -{ - printf("%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"\n", - eventType != 0 ? emscripten_event_type_to_string(eventType) : "Gamepad state", e->timestamp, e->connected, e->index, - e->numAxes, e->numButtons, e->id, e->mapping); - - if (e->connected) - { - for(int i = 0; i < e->numAxes; ++i) - printf("Axis %d: %g\n", i, e->axis[i]); - - for(int i = 0; i < e->numButtons; ++i) - printf("Button %d: Digital: %d, Analog: %g\n", i, e->digitalButton[i], e->analogButton[i]); - } - - return 0; -} - -const char *beforeunload_callback(int eventType, const void *reserved, void *userData) -{ -#ifdef REPORT_RESULT - return ""; // For test harness, don't show a confirmation dialog to not block and keep the test runner automated. -#else - return "Do you really want to leave the page?"; -#endif -} - -void formatTime(char *str, int seconds) -{ - int h = seconds / (60*60); - seconds -= h*60*60; - int m = seconds / 60; - seconds -= m*60; - if (h > 0) - { - sprintf(str, "%dh:%02dm:%02ds", h, m, seconds); - } - else - { - sprintf(str, "%02dm:%02ds", m, seconds); - } -} - -EM_BOOL battery_callback(int eventType, const emscripten_BatteryEvent *e, void *userData) -{ - char t1[64]; - formatTime(t1, (int)e->chargingTime); - char t2[64]; - formatTime(t2, (int)e->dischargingTime); - printf("%s: chargingTime: %s, dischargingTime: %s, level: %g%%, charging: %d\n", - emscripten_event_type_to_string(eventType), t1, t2, e->level*100, e->charging); - - return 0; -} - -EM_BOOL webglcontext_callback(int eventType, const void *reserved, void *userData) -{ - printf("%s.\n", emscripten_event_type_to_string(eventType)); - - return 0; -} - -emscripten_GamepadEvent prevState[32]; -int prevNumGamepads = 0; - -void mainloop() -{ - int numGamepads = emscripten_get_num_gamepads(); - if (numGamepads != prevNumGamepads) - { - printf("Number of connected gamepads: %d\n", numGamepads); - prevNumGamepads = numGamepads; - } - - for(int i = 0; i < numGamepads && i < 32; ++i) - { - emscripten_GamepadEvent ge; - int failed = emscripten_get_gamepad_status(i, &ge); - if (!failed) - { - int g = ge.index; - for(int j = 0; j < ge.numAxes; ++j) - { - if (ge.axis[j] != prevState[g].axis[j]) - printf("Gamepad %d, axis %d: %g\n", g, j, ge.axis[j]); - } - - for(int j = 0; j < ge.numButtons; ++j) - { - if (ge.analogButton[j] != prevState[g].analogButton[j] || ge.digitalButton[j] != prevState[g].digitalButton[j]) - printf("Gamepad %d, button %d: Digital: %d, Analog: %g\n", g, j, ge.digitalButton[j], ge.analogButton[j]); - } - prevState[g] = ge; - } - } - -} - -#ifdef REPORT_RESULT -void report_result(void *arg) -{ - int result = 0; - REPORT_RESULT(); -} -#endif - -int main() -{ - emscripten_set_keypress_callback(0, 0, 1, key_callback); - emscripten_set_keydown_callback(0, 0, 1, key_callback); - emscripten_set_keyup_callback(0, 0, 1, key_callback); - - emscripten_set_click_callback(0, 0, 1, mouse_callback); - emscripten_set_mousedown_callback(0, 0, 1, mouse_callback); - emscripten_set_mouseup_callback(0, 0, 1, mouse_callback); - emscripten_set_dblclick_callback(0, 0, 1, mouse_callback); - emscripten_set_mousemove_callback(0, 0, 1, mouse_callback); - - emscripten_set_wheel_callback(0, 0, 1, wheel_callback); - - emscripten_set_resize_callback(0, 0, 1, uievent_callback); - emscripten_set_scroll_callback(0, 0, 1, uievent_callback); - - emscripten_set_blur_callback(0, 0, 1, focusevent_callback); - emscripten_set_focus_callback(0, 0, 1, focusevent_callback); - emscripten_set_focusin_callback(0, 0, 1, focusevent_callback); - emscripten_set_focusout_callback(0, 0, 1, focusevent_callback); - - emscripten_set_deviceorientation_callback(0, 1, deviceorientation_callback); - emscripten_set_devicemotion_callback(0, 1, devicemotion_callback); - - emscripten_set_orientationchange_callback(0, 1, orientationchange_callback); - - // Test the polling of orientation. - emscripten_OrientationChangeEvent oce; - emscripten_get_orientation_status(&oce); - printf("The current orientation is:\n"); - orientationchange_callback(EMSCRIPTEN_EVENT_ORIENTATIONCHANGE, &oce, 0); - - int newOrientation = (oce.orientationIndex == EMSCRIPTEN_ORIENTATION_PORTRAIT_PRIMARY - || oce.orientationIndex == EMSCRIPTEN_ORIENTATION_PORTRAIT_SECONDARY) ? EMSCRIPTEN_ORIENTATION_LANDSCAPE_PRIMARY : EMSCRIPTEN_ORIENTATION_PORTRAIT_PRIMARY; - printf("Locking orientation to state %d..\n", newOrientation); - // Test locking of orientation. - int failed = emscripten_lock_orientation(newOrientation); - - if (failed) - printf("No support for orientation lock!\n"); - - emscripten_get_orientation_status(&oce); - printf("The current orientation is after locking:\n"); - orientationchange_callback(18, &oce, 0); - - printf("Unlocking orientation..\n"); - emscripten_unlock_orientation(); - - emscripten_FullscreenChangeEvent fsce; - emscripten_get_fullscreen_status(&fsce); - printf("The current fullscreen status is:\n"); - fullscreenchange_callback(EMSCRIPTEN_EVENT_FULLSCREENCHANGE, &fsce, 0); - - emscripten_set_fullscreenchange_callback(0, 1, fullscreenchange_callback); - - // These won't do anything, since fullscreen must be requested in an event handler, - // but call these anyways to confirm that they don't crash in an exception in the test suite. - failed = emscripten_request_fullscreen(0, 1); - if (failed != 0 && failed != 3) - printf("Fullscreen request failed! (%d)\n", failed); - emscripten_exit_fullscreen(); - - emscripten_PointerlockChangeEvent plce; - emscripten_get_pointerlock_status(&plce); - printf("The current pointerlock status is:\n"); - pointerlockchange_callback(EMSCRIPTEN_EVENT_POINTERLOCKCHANGE, &plce, 0); - - emscripten_set_pointerlockchange_callback(0, 1, pointerlockchange_callback); - - // These won't do anything, since pointer lock must be requested in an event handler, - // but call these anyways to confirm that they don't crash in an exception in the test suite. - failed = emscripten_request_pointerlock(0, 1); - if (failed != 0 && failed != 3) - printf("Pointer lock request failed! (%d)\n", failed); - emscripten_exit_pointerlock(); - - int vibratePattern[] = { - 150, 500, - 300, 500, - 450 - }; - emscripten_vibrate_pattern(vibratePattern, sizeof(vibratePattern)/sizeof(vibratePattern[0])); - - emscripten_VisibilityChangeEvent vce; - emscripten_get_visibility_status(&vce); - printf("Current visibility status:\n"); - visibilitychange_callback(EMSCRIPTEN_EVENT_VISIBILITYCHANGE, &vce, 0); - - emscripten_set_visibilitychange_callback(0, 1, visibilitychange_callback); - - emscripten_set_touchstart_callback(0, 0, 1, touch_callback); - emscripten_set_touchend_callback(0, 0, 1, touch_callback); - emscripten_set_touchmove_callback(0, 0, 1, touch_callback); - emscripten_set_touchcancel_callback(0, 0, 1, touch_callback); - - emscripten_set_gamepadconnected_callback(0, 1, gamepad_callback); - emscripten_set_gamepaddisconnected_callback(0, 1, gamepad_callback); - - emscripten_set_main_loop(mainloop, 10, 0); - - emscripten_set_beforeunload_callback(0, beforeunload_callback); - - emscripten_set_batterychargingchange_callback(0, battery_callback); - emscripten_set_batterylevelchange_callback(0, battery_callback); - - emscripten_BatteryEvent bs; - failed = emscripten_get_battery_status(&bs); - if (failed) { - printf("Browser can not provide Battery Status information!\n"); - } else { - printf("Current battery status:\n"); - battery_callback(EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE, &bs, 0); - } - - emscripten_set_webglcontextlost_callback(0, 0, 1, webglcontext_callback); - emscripten_set_webglcontextrestored_callback(0, 0, 1, webglcontext_callback); - - /* For the events to function, one must either call emscripten_set_main_loop or enable Module.noExitRuntime by some other means. - Otherwise the application will exit after leaving main(), and the atexit handlers will clean up all event hooks (by design). */ - EM_ASM(Module['noExitRuntime'] = true); - -#ifdef REPORT_RESULT - // Keep the page running for a moment. - emscripten_async_call(report_result, 0, 5000); -#endif - return 0; -} diff --git a/tests/test_html5.c b/tests/test_html5.c new file mode 100644 index 000000000..77ddea98a --- /dev/null +++ b/tests/test_html5.c @@ -0,0 +1,474 @@ +#include +#include +#include +#include + +static inline const char *emscripten_event_type_to_string(int eventType) { + const char *events[] = { "(invalid)", "(none)", "keypress", "keydown", "keyup", "click", "mousedown", "mouseup", "dblclick", "mousemove", "wheel", "resize", + "scroll", "blur", "focus", "focusin", "focusout", "deviceorientation", "devicemotion", "orientationchange", "fullscreenchange", "pointerlockchange", + "visibilitychange", "touchstart", "touchend", "touchmove", "touchcancel", "gamepadconnected", "gamepaddisconnected", "beforeunload", + "batterychargingchange", "batterylevelchange", "webglcontextlost", "webglcontextrestored", "(invalid)" }; + ++eventType; + if (eventType < 0) eventType = 0; + if (eventType >= sizeof(events)/sizeof(events[0])) eventType = sizeof(events)/sizeof(events[0])-1; + return events[eventType]; +} + +const char *emscripten_result_to_string(EMSCRIPTEN_RESULT result) { + if (result == EMSCRIPTEN_RESULT_SUCCESS) return "EMSCRIPTEN_RESULT_SUCCESS"; + if (result == EMSCRIPTEN_RESULT_DEFERRED) return "EMSCRIPTEN_RESULT_DEFERRED"; + if (result == EMSCRIPTEN_RESULT_NOT_SUPPORTED) return "EMSCRIPTEN_RESULT_NOT_SUPPORTED"; + if (result == EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED) return "EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED"; + if (result == EMSCRIPTEN_RESULT_INVALID_TARGET) return "EMSCRIPTEN_RESULT_INVALID_TARGET"; + if (result == EMSCRIPTEN_RESULT_UNKNOWN_TARGET) return "EMSCRIPTEN_RESULT_UNKNOWN_TARGET"; + if (result == EMSCRIPTEN_RESULT_INVALID_PARAM) return "EMSCRIPTEN_RESULT_INVALID_PARAM"; + if (result == EMSCRIPTEN_RESULT_FAILED) return "EMSCRIPTEN_RESULT_FAILED"; + if (result == EMSCRIPTEN_RESULT_NO_DATA) return "EMSCRIPTEN_RESULT_NO_DATA"; + return "Unknown EMSCRIPTEN_RESULT!"; +} + +#define TEST_RESULT(x) if (ret != EMSCRIPTEN_RESULT_SUCCESS) printf("%s returned %s.\n", #x, emscripten_result_to_string(ret)); + +// The event handler functions can return 1 to suppress the event and disable the default action. That calls event.preventDefault(); +// Returning 0 signals that the event was not consumed by the code, and will allow the event to pass on and bubble up normally. +EM_BOOL key_callback(int eventType, const EmscriptenKeyboardEvent *e, void *userData) +{ + printf("%s, key: \"%s\", code: \"%s\", location: %lu,%s%s%s%s repeat: %d, locale: \"%s\", char: \"%s\", charCode: %lu, keyCode: %lu, which: %lu\n", + emscripten_event_type_to_string(eventType), e->key, e->code, e->location, + e->ctrlKey ? " CTRL" : "", e->shiftKey ? " SHIFT" : "", e->altKey ? " ALT" : "", e->metaKey ? " META" : "", + e->repeat, e->locale, e->charValue, e->charCode, e->keyCode, e->which); + + if (eventType == EMSCRIPTEN_EVENT_KEYPRESS && (!strcmp(e->key, "f") || e->which == 102)) { + EmscriptenFullscreenChangeEvent fsce; + EMSCRIPTEN_RESULT ret = emscripten_get_fullscreen_status(&fsce); + TEST_RESULT(emscripten_get_fullscreen_status); + if (!fsce.isFullscreen) { + printf("Requesting fullscreen..\n"); + ret = emscripten_request_fullscreen(0, 1); + TEST_RESULT(emscripten_request_fullscreen); + } else { + printf("Exiting fullscreen..\n"); + ret = emscripten_exit_fullscreen(); + TEST_RESULT(emscripten_exit_fullscreen); + ret = emscripten_get_fullscreen_status(&fsce); + TEST_RESULT(emscripten_get_fullscreen_status); + if (fsce.isFullscreen) { + fprintf(stderr, "Fullscreen exit did not work!\n"); + } + } + } + + if (eventType == EMSCRIPTEN_EVENT_KEYPRESS && (!strcmp(e->key, "p") || e->which == 112)) { + EmscriptenPointerlockChangeEvent plce; + EMSCRIPTEN_RESULT ret = emscripten_get_pointerlock_status(&plce); + TEST_RESULT(emscripten_get_pointerlock_status); + if (!plce.isActive) { + printf("Requesting pointer lock..\n"); + ret = emscripten_request_pointerlock(0, 1); + TEST_RESULT(emscripten_request_pointerlock); + } else { + printf("Exiting pointer lock..\n"); + ret = emscripten_exit_pointerlock(); + TEST_RESULT(emscripten_exit_pointerlock); + ret = emscripten_get_pointerlock_status(&plce); + TEST_RESULT(emscripten_get_pointerlock_status); + if (plce.isActive) { + fprintf(stderr, "Pointer lock exit did not work!\n"); + } + } + } + + return 0; +} + +EM_BOOL mouse_callback(int eventType, const EmscriptenMouseEvent *e, void *userData) +{ + printf("%s, screen: (%ld,%ld), client: (%ld,%ld),%s%s%s%s button: %hu, buttons: %hu, movement: (%ld,%ld), canvas: (%ld,%ld)\n", + emscripten_event_type_to_string(eventType), e->screenX, e->screenY, e->clientX, e->clientY, + e->ctrlKey ? " CTRL" : "", e->shiftKey ? " SHIFT" : "", e->altKey ? " ALT" : "", e->metaKey ? " META" : "", + e->button, e->buttons, e->movementX, e->movementY, e->canvasX, e->canvasY); + + return 0; +} + +EM_BOOL wheel_callback(int eventType, const EmscriptenWheelEvent *e, void *userData) +{ + printf("%s, screen: (%ld,%ld), client: (%ld,%ld),%s%s%s%s button: %hu, buttons: %hu, canvas: (%ld,%ld), delta:(%g,%g,%g), deltaMode:%lu\n", + emscripten_event_type_to_string(eventType), e->mouse.screenX, e->mouse.screenY, e->mouse.clientX, e->mouse.clientY, + e->mouse.ctrlKey ? " CTRL" : "", e->mouse.shiftKey ? " SHIFT" : "", e->mouse.altKey ? " ALT" : "", e->mouse.metaKey ? " META" : "", + e->mouse.button, e->mouse.buttons, e->mouse.canvasX, e->mouse.canvasY, + (float)e->deltaX, (float)e->deltaY, (float)e->deltaZ, e->deltaMode); + + return 0; +} + +EM_BOOL uievent_callback(int eventType, const EmscriptenUiEvent *e, void *userData) +{ + printf("%s, detail: %ld, document.body.client size: (%d,%d), window.inner size: (%d,%d), scrollPos: (%d, %d)\n", + emscripten_event_type_to_string(eventType), e->detail, e->documentBodyClientWidth, e->documentBodyClientHeight, + e->windowInnerWidth, e->windowInnerHeight, e->scrollTop, e->scrollLeft); + + return 0; +} + +EM_BOOL focusevent_callback(int eventType, const EmscriptenFocusEvent *e, void *userData) +{ + printf("%s, nodeName: \"%s\", id: \"%s\"\n", emscripten_event_type_to_string(eventType), e->nodeName, e->id[0] == '\0' ? "(empty string)" : e->id); + + return 0; +} + +EM_BOOL deviceorientation_callback(int eventType, const EmscriptenDeviceOrientationEvent *e, void *userData) +{ + printf("%s, (%g, %g, %g)\n", emscripten_event_type_to_string(eventType), e->alpha, e->beta, e->gamma); + + return 0; +} + +EM_BOOL devicemotion_callback(int eventType, const EmscriptenDeviceMotionEvent *e, void *userData) +{ + printf("%s, accel: (%g, %g, %g), accelInclGravity: (%g, %g, %g), rotationRate: (%g, %g, %g)\n", + emscripten_event_type_to_string(eventType), + e->accelerationX, e->accelerationY, e->accelerationZ, + e->accelerationIncludingGravityX, e->accelerationIncludingGravityY, e->accelerationIncludingGravityZ, + e->rotationRateAlpha, e->rotationRateBeta, e->rotationRateGamma); + + return 0; +} + +EM_BOOL orientationchange_callback(int eventType, const EmscriptenOrientationChangeEvent *e, void *userData) +{ + printf("%s, orientationAngle: %d, orientationIndex: %d\n", emscripten_event_type_to_string(eventType), e->orientationAngle, e->orientationIndex); + + return 0; +} + +EM_BOOL fullscreenchange_callback(int eventType, const EmscriptenFullscreenChangeEvent *e, void *userData) +{ + printf("%s, isFullscreen: %d, fullscreenEnabled: %d, fs element nodeName: \"%s\", fs element id: \"%s\"\n", + emscripten_event_type_to_string(eventType), e->isFullscreen, e->fullscreenEnabled, e->nodeName, e->id); + + return 0; +} + +EM_BOOL pointerlockchange_callback(int eventType, const EmscriptenPointerlockChangeEvent *e, void *userData) +{ + printf("%s, isActive: %d, pointerlock element nodeName: \"%s\", id: \"%s\"\n", + emscripten_event_type_to_string(eventType), e->isActive, e->nodeName, e->id); + + return 0; +} + +EM_BOOL visibilitychange_callback(int eventType, const EmscriptenVisibilityChangeEvent *e, void *userData) +{ + printf("%s, hidden: %d, visibilityState: %d\n", emscripten_event_type_to_string(eventType), e->hidden, e->visibilityState); + + return 0; +} + +EM_BOOL touch_callback(int eventType, const EmscriptenTouchEvent *e, void *userData) +{ + printf("%s, numTouches: %d %s%s%s%s\n", + emscripten_event_type_to_string(eventType), e->numTouches, + e->ctrlKey ? " CTRL" : "", e->shiftKey ? " SHIFT" : "", e->altKey ? " ALT" : "", e->metaKey ? " META" : ""); + for(int i = 0; i < e->numTouches; ++i) + { + const EmscriptenTouchPoint *t = &e->touches[i]; + printf(" %ld: screen: (%ld,%ld), client: (%ld,%ld), page: (%ld,%ld), isChanged: %d, onTarget: %d, canvas: (%ld, %ld)\n", + t->identifier, t->screenX, t->screenY, t->clientX, t->clientY, t->pageX, t->pageY, t->isChanged, t->onTarget, t->canvasX, t->canvasY); + } + + return 0; +} + +EM_BOOL gamepad_callback(int eventType, const EmscriptenGamepadEvent *e, void *userData) +{ + printf("%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"\n", + eventType != 0 ? emscripten_event_type_to_string(eventType) : "Gamepad state", e->timestamp, e->connected, e->index, + e->numAxes, e->numButtons, e->id, e->mapping); + + if (e->connected) + { + for(int i = 0; i < e->numAxes; ++i) + printf("Axis %d: %g\n", i, e->axis[i]); + + for(int i = 0; i < e->numButtons; ++i) + printf("Button %d: Digital: %d, Analog: %g\n", i, e->digitalButton[i], e->analogButton[i]); + } + + return 0; +} + +const char *beforeunload_callback(int eventType, const void *reserved, void *userData) +{ +#ifdef REPORT_RESULT + return ""; // For test harness, don't show a confirmation dialog to not block and keep the test runner automated. +#else + return "Do you really want to leave the page?"; +#endif +} + +void formatTime(char *str, int seconds) +{ + int h = seconds / (60*60); + seconds -= h*60*60; + int m = seconds / 60; + seconds -= m*60; + if (h > 0) + { + sprintf(str, "%dh:%02dm:%02ds", h, m, seconds); + } + else + { + sprintf(str, "%02dm:%02ds", m, seconds); + } +} + +EM_BOOL battery_callback(int eventType, const EmscriptenBatteryEvent *e, void *userData) +{ + char t1[64]; + formatTime(t1, (int)e->chargingTime); + char t2[64]; + formatTime(t2, (int)e->dischargingTime); + printf("%s: chargingTime: %s, dischargingTime: %s, level: %g%%, charging: %d\n", + emscripten_event_type_to_string(eventType), t1, t2, e->level*100, e->charging); + + return 0; +} + +EM_BOOL webglcontext_callback(int eventType, const void *reserved, void *userData) +{ + printf("%s.\n", emscripten_event_type_to_string(eventType)); + + return 0; +} + +EmscriptenGamepadEvent prevState[32]; +int prevNumGamepads = 0; + +void mainloop() +{ + int numGamepads = emscripten_get_num_gamepads(); + if (numGamepads != prevNumGamepads) + { + if (numGamepads == EMSCRIPTEN_RESULT_NOT_SUPPORTED) { + printf("emscripten_get_num_gamepads returned EMSCRIPTEN_RESULT_NOT_SUPPORTED.\n"); + emscripten_cancel_main_loop(); + return; + } else { + printf("Number of connected gamepads: %d\n", numGamepads); + } + prevNumGamepads = numGamepads; + } + + for(int i = 0; i < numGamepads && i < 32; ++i) + { + EmscriptenGamepadEvent ge; + int failed = emscripten_get_gamepad_status(i, &ge); + if (!failed) + { + int g = ge.index; + for(int j = 0; j < ge.numAxes; ++j) + { + if (ge.axis[j] != prevState[g].axis[j]) + printf("Gamepad %d, axis %d: %g\n", g, j, ge.axis[j]); + } + + for(int j = 0; j < ge.numButtons; ++j) + { + if (ge.analogButton[j] != prevState[g].analogButton[j] || ge.digitalButton[j] != prevState[g].digitalButton[j]) + printf("Gamepad %d, button %d: Digital: %d, Analog: %g\n", g, j, ge.digitalButton[j], ge.analogButton[j]); + } + prevState[g] = ge; + } + } + +} + +#ifdef REPORT_RESULT +void report_result(void *arg) +{ + int result = 0; + REPORT_RESULT(); +} +#endif + +int main() +{ + + EMSCRIPTEN_RESULT ret = emscripten_set_keypress_callback(0, 0, 1, key_callback); + TEST_RESULT(emscripten_set_keypress_callback); + ret = emscripten_set_keydown_callback(0, 0, 1, key_callback); + TEST_RESULT(emscripten_set_keydown_callback); + ret = emscripten_set_keyup_callback(0, 0, 1, key_callback); + TEST_RESULT(emscripten_set_keyup_callback); + + ret = emscripten_set_click_callback(0, 0, 1, mouse_callback); + TEST_RESULT(emscripten_set_click_callback); + ret = emscripten_set_mousedown_callback(0, 0, 1, mouse_callback); + TEST_RESULT(emscripten_set_mousedown_callback); + ret = emscripten_set_mouseup_callback(0, 0, 1, mouse_callback); + TEST_RESULT(emscripten_set_mouseup_callback); + ret = emscripten_set_dblclick_callback(0, 0, 1, mouse_callback); + TEST_RESULT(emscripten_set_dblclick_callback); + ret = emscripten_set_mousemove_callback(0, 0, 1, mouse_callback); + TEST_RESULT(emscripten_set_mousemove_callback); + + ret = emscripten_set_wheel_callback(0, 0, 1, wheel_callback); + TEST_RESULT(emscripten_set_wheel_callback); + + ret = emscripten_set_resize_callback(0, 0, 1, uievent_callback); + TEST_RESULT(emscripten_set_resize_callback); + ret = emscripten_set_scroll_callback(0, 0, 1, uievent_callback); + TEST_RESULT(emscripten_set_scroll_callback); + + ret = emscripten_set_blur_callback(0, 0, 1, focusevent_callback); + TEST_RESULT(emscripten_set_blur_callback); + ret = emscripten_set_focus_callback(0, 0, 1, focusevent_callback); + TEST_RESULT(emscripten_set_focus_callback); + ret = emscripten_set_focusin_callback(0, 0, 1, focusevent_callback); + TEST_RESULT(emscripten_set_focusin_callback); + ret = emscripten_set_focusout_callback(0, 0, 1, focusevent_callback); + TEST_RESULT(emscripten_set_focusout_callback); + + ret = emscripten_set_deviceorientation_callback(0, 1, deviceorientation_callback); + TEST_RESULT(emscripten_set_deviceorientation_callback); + ret = emscripten_set_devicemotion_callback(0, 1, devicemotion_callback); + TEST_RESULT(emscripten_set_devicemotion_callback); + + ret = emscripten_set_orientationchange_callback(0, 1, orientationchange_callback); + TEST_RESULT(emscripten_set_orientationchange_callback); + + // Test the polling of orientation. + EmscriptenOrientationChangeEvent oce; + ret = emscripten_get_orientation_status(&oce); + TEST_RESULT(emscripten_get_orientation_status); + if (ret == EMSCRIPTEN_RESULT_SUCCESS) { + printf("The current orientation is:\n"); + orientationchange_callback(EMSCRIPTEN_EVENT_ORIENTATIONCHANGE, &oce, 0); + } + + int newOrientation = (oce.orientationIndex == EMSCRIPTEN_ORIENTATION_PORTRAIT_PRIMARY + || oce.orientationIndex == EMSCRIPTEN_ORIENTATION_PORTRAIT_SECONDARY) ? EMSCRIPTEN_ORIENTATION_LANDSCAPE_PRIMARY : EMSCRIPTEN_ORIENTATION_PORTRAIT_PRIMARY; + // Test locking of orientation. + ret = emscripten_lock_orientation(newOrientation); + TEST_RESULT(emscripten_lock_orientation); + if (ret == EMSCRIPTEN_RESULT_SUCCESS) { + printf("Locked orientation to state %d.\n", newOrientation); + } + + ret = emscripten_get_orientation_status(&oce); + TEST_RESULT(emscripten_get_orientation_status); + if (ret == EMSCRIPTEN_RESULT_SUCCESS) { + printf("The current orientation is after locking:\n"); + orientationchange_callback(18, &oce, 0); + } + + ret = emscripten_unlock_orientation(); + TEST_RESULT(emscripten_unlock_orientation); + if (ret == EMSCRIPTEN_RESULT_SUCCESS) { + printf("Unlocked orientation.\n"); + } + + EmscriptenFullscreenChangeEvent fsce; + ret = emscripten_get_fullscreen_status(&fsce); + TEST_RESULT(emscripten_get_fullscreen_status); + if (ret == EMSCRIPTEN_RESULT_SUCCESS) { + printf("The current fullscreen status is:\n"); + fullscreenchange_callback(EMSCRIPTEN_EVENT_FULLSCREENCHANGE, &fsce, 0); + } + + ret = emscripten_set_fullscreenchange_callback(0, 0, 1, fullscreenchange_callback); + TEST_RESULT(emscripten_set_fullscreenchange_callback); + + // These won't do anything, since fullscreen must be requested in an event handler, + // but call these anyways to confirm that they don't crash in an exception in the test suite. + ret = emscripten_request_fullscreen(0, 1); + TEST_RESULT(emscripten_request_fullscreen); + ret = emscripten_exit_fullscreen(); + TEST_RESULT(emscripten_exit_fullscreen); + + EmscriptenPointerlockChangeEvent plce; + ret = emscripten_get_pointerlock_status(&plce); + TEST_RESULT(emscripten_get_pointerlock_status); + if (ret == EMSCRIPTEN_RESULT_SUCCESS) { + printf("The current pointerlock status is:\n"); + pointerlockchange_callback(EMSCRIPTEN_EVENT_POINTERLOCKCHANGE, &plce, 0); + } + + ret = emscripten_set_pointerlockchange_callback(0, 0, 1, pointerlockchange_callback); + TEST_RESULT(emscripten_set_pointerlockchange_callback); + + // These won't do anything, since pointer lock must be requested in an event handler, + // but call these anyways to confirm that they don't crash in an exception in the test suite. + ret = emscripten_request_pointerlock(0, 1); + TEST_RESULT(emscripten_request_pointerlock); + ret = emscripten_exit_pointerlock(); + TEST_RESULT(emscripten_exit_pointerlock); + + int vibratePattern[] = { + 150, 500, + 300, 500, + 450 + }; + ret = emscripten_vibrate_pattern(vibratePattern, sizeof(vibratePattern)/sizeof(vibratePattern[0])); + TEST_RESULT(emscripten_vibrate_pattern); + + EmscriptenVisibilityChangeEvent vce; + ret = emscripten_get_visibility_status(&vce); + TEST_RESULT(emscripten_get_visibility_status); + if (ret == EMSCRIPTEN_RESULT_SUCCESS) { + printf("Current visibility status:\n"); + visibilitychange_callback(EMSCRIPTEN_EVENT_VISIBILITYCHANGE, &vce, 0); + } + + ret = emscripten_set_visibilitychange_callback(0, 1, visibilitychange_callback); + TEST_RESULT(emscripten_set_visibilitychange_callback); + + ret = emscripten_set_touchstart_callback(0, 0, 1, touch_callback); + TEST_RESULT(emscripten_set_touchstart_callback); + ret = emscripten_set_touchend_callback(0, 0, 1, touch_callback); + TEST_RESULT(emscripten_set_touchend_callback); + ret = emscripten_set_touchmove_callback(0, 0, 1, touch_callback); + TEST_RESULT(emscripten_set_touchmove_callback); + ret = emscripten_set_touchcancel_callback(0, 0, 1, touch_callback); + TEST_RESULT(emscripten_set_touchcancel_callback); + + ret = emscripten_set_gamepadconnected_callback(0, 1, gamepad_callback); + TEST_RESULT(emscripten_set_gamepadconnected_callback); + ret = emscripten_set_gamepaddisconnected_callback(0, 1, gamepad_callback); + TEST_RESULT(emscripten_set_gamepaddisconnected_callback); + + emscripten_set_main_loop(mainloop, 10, 0); + + ret = emscripten_set_beforeunload_callback(0, beforeunload_callback); + TEST_RESULT(emscripten_set_beforeunload_callback); + + ret = emscripten_set_batterychargingchange_callback(0, battery_callback); + TEST_RESULT(emscripten_set_batterychargingchange_callback); + ret = emscripten_set_batterylevelchange_callback(0, battery_callback); + TEST_RESULT(emscripten_set_batterylevelchange_callback); + + EmscriptenBatteryEvent bs; + ret = emscripten_get_battery_status(&bs); + TEST_RESULT(emscripten_get_battery_status); + if (ret == EMSCRIPTEN_RESULT_SUCCESS) { + printf("Current battery status:\n"); + battery_callback(EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE, &bs, 0); + } + + ret = emscripten_set_webglcontextlost_callback(0, 0, 1, webglcontext_callback); + TEST_RESULT(emscripten_set_webglcontextlost_callback); + ret = emscripten_set_webglcontextrestored_callback(0, 0, 1, webglcontext_callback); + TEST_RESULT(emscripten_set_webglcontextrestored_callback); + + /* For the events to function, one must either call emscripten_set_main_loop or enable Module.noExitRuntime by some other means. + Otherwise the application will exit after leaving main(), and the atexit handlers will clean up all event hooks (by design). */ + EM_ASM(Module['noExitRuntime'] = true); + +#ifdef REPORT_RESULT + // Keep the page running for a moment. + emscripten_async_call(report_result, 0, 5000); +#endif + return 0; +}