diff --git a/core/sys/wasm/js/events.odin b/core/sys/wasm/js/events.odin index 0ef3e9970..905b3eba9 100644 --- a/core/sys/wasm/js/events.odin +++ b/core/sys/wasm/js/events.odin @@ -313,14 +313,14 @@ foreign dom_lib { dispatch_custom_event :: proc(id: string, name: string, options := Event_Options{}) -> bool --- } -add_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), flags := Listener_Flags{}) -> bool { +add_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool { @(default_calling_convention="contextless") foreign dom_lib { @(link_name="add_event_listener") - _add_event_listener :: proc(id: string, name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool, prevent_default: bool, stop_prop: bool, stop_imm_prop: bool) -> bool --- + _add_event_listener :: proc(id: string, name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool --- } // TODO: Pointer_Lock_Change etc related stuff for all different browsers - return _add_event_listener(id, event_kind_string[kind], kind, user_data, callback, .Use_Capture in flags, .Prevent_Default in flags, .Stop_Propagation in flags, .Stop_Immediate_Propagation in flags) + return _add_event_listener(id, event_kind_string[kind], kind, user_data, callback, use_capture) } remove_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event)) -> bool { @@ -332,13 +332,13 @@ remove_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, c return _remove_event_listener(id, event_kind_string[kind], user_data, callback) } -add_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), flags := Listener_Flags{}) -> bool { +add_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool { @(default_calling_convention="contextless") foreign dom_lib { @(link_name="add_window_event_listener") - _add_window_event_listener :: proc(name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool, prevent_default: bool, stop_prop: bool, stop_imm_prop: bool) -> bool --- + _add_window_event_listener :: proc(name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool --- } - return _add_window_event_listener(event_kind_string[kind], kind, user_data, callback, .Use_Capture in flags, .Prevent_Default in flags, .Stop_Propagation in flags, .Stop_Immediate_Propagation in flags) + return _add_window_event_listener(event_kind_string[kind], kind, user_data, callback, use_capture) } remove_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event)) -> bool { @@ -357,15 +357,14 @@ remove_event_listener_from_event :: proc(e: Event) -> bool { return remove_event_listener(e.id, e.kind, e.user_data, e.callback) } -add_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event), flags := Listener_Flags{}) -> bool { +add_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool { @(default_calling_convention="contextless") foreign dom_lib { @(link_name="add_event_listener") - _add_event_listener :: proc(id: string, name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool, prevent_default: bool, stop_prop: bool, stop_imm_prop: bool) -> bool --- + _add_event_listener :: proc(id: string, name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool --- } - return _add_event_listener(id, name, .Custom, user_data, callback, .Use_Capture in flags, .Prevent_Default in flags, .Stop_Propagation in flags, .Stop_Immediate_Propagation in flags) + return _add_event_listener(id, name, .Custom, user_data, callback, use_capture) } - remove_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event)) -> bool { @(default_calling_convention="contextless") foreign dom_lib { diff --git a/core/sys/wasm/js/odin.js b/core/sys/wasm/js/odin.js index 47facc676..5cc174665 100644 --- a/core/sys/wasm/js/odin.js +++ b/core/sys/wasm/js/odin.js @@ -1259,13 +1259,30 @@ class WebGLInterface { }; -function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory, eventQueue, event_temp) { +function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory, eventHookCallback) { const MAX_INFO_CONSOLE_LINES = 512; let infoConsoleLines = new Array(); let currentLine = {}; currentLine[false] = ""; currentLine[true] = ""; let prevIsError = false; + + let event_temp = {}; + + const onEventReceived = (event_data, data, callback) => { + event_temp.data = event_data; + + const exports = wasmMemoryInterface.exports; + const odin_ctx = exports.default_context_ptr(); + + const mute = eventHookCallback && !eventHookCallback(event_data.event, data, callback); + + if (!mute) { + exports.odin_dom_do_event_callback(data, callback, odin_ctx); + } + + event_temp.data = null; + }; const writeToConsole = (line, isError) => { if (!line) { @@ -1579,7 +1596,7 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory, ev } }, - add_event_listener: (id_ptr, id_len, name_ptr, name_len, name_code, data, callback, use_capture, prevent_default, stop_prop, stop_imm_prop) => { + add_event_listener: (id_ptr, id_len, name_ptr, name_len, name_code, data, callback, use_capture) => { let id = wasmMemoryInterface.loadString(id_ptr, id_len); let name = wasmMemoryInterface.loadString(name_ptr, name_len); let element = getElement(id); @@ -1594,18 +1611,14 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory, ev event_data.event = e; event_data.name_code = name_code; - if (prevent_default) e.preventDefault(); - if (stop_prop) e.stopPropagation(); - if (stop_imm_prop) e.stopImmediatePropagation(); - - eventQueue.push({event_data: event_data, data: data, callback: callback}); + onEventReceived(event_data, data, callback); }; wasmMemoryInterface.listenerMap[{data: data, callback: callback}] = listener; element.addEventListener(name, listener, !!use_capture); return true; }, - add_window_event_listener: (name_ptr, name_len, name_code, data, callback, use_capture, prevent_default, stop_prop, stop_imm_prop) => { + add_window_event_listener: (name_ptr, name_len, name_code, data, callback, use_capture) => { let name = wasmMemoryInterface.loadString(name_ptr, name_len); let element = window; let listener = (e) => { @@ -1615,11 +1628,7 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory, ev event_data.event = e; event_data.name_code = name_code; - if (prevent_default) e.preventDefault(); - if (stop_prop) e.stopPropagation(); - if (stop_imm_prop) e.stopImmediatePropagation(); - - eventQueue.push({event_data: event_data, data: data, callback: callback}); + onEventReceived(event_data, data, callback); }; wasmMemoryInterface.listenerMap[{data: data, callback: callback}] = listener; element.addEventListener(name, listener, !!use_capture); @@ -1900,23 +1909,30 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory, ev }; }; +/** + * A callback used to intersept events that are being dispatched to the application. + * @callback EventHookCallback + * @param {Object} [event] - The event that is about to be sent to the application. + * @param {Object} [data] - The user data that was passed in when the event listener for {@param event} was registered. + * @param {Object} [callback] - The callback that was passed in when the event listener for {@param event} was registered. + * @return {bool} If false, the event will not be sent to the application. + */ + /** * @param {string} wasmPath - Path to the WASM module to run * @param {?HTMLPreElement} consoleElement - Optional console/pre element to append output to, in addition to the console * @param {any} extraForeignImports - Imports, in addition to the default runtime to provide the module * @param {?WasmMemoryInterface} wasmMemoryInterface - Optional memory to use instead of the defaults * @param {?int} intSize - Size (in bytes) of the integer type, should be 4 on `js_wasm32` and 8 on `js_wasm64p32` + * @param {?EventHookCallback} eventHookCallback - Callback that will be invoked when an event is dispatched to the application */ -async function runWasm(wasmPath, consoleElement, extraForeignImports, wasmMemoryInterface, intSize = 4) { +async function runWasm(wasmPath, consoleElement, extraForeignImports, wasmMemoryInterface, intSize = 4, eventHookCallback = null) { if (!wasmMemoryInterface) { wasmMemoryInterface = new WasmMemoryInterface(); } wasmMemoryInterface.setIntSize(intSize); - let eventQueue = new Array(); - let event_temp = {}; - - let imports = odinSetupDefaultImports(wasmMemoryInterface, consoleElement, wasmMemoryInterface.memory, eventQueue, event_temp); + let imports = odinSetupDefaultImports(wasmMemoryInterface, consoleElement, wasmMemoryInterface.memory, eventHookCallback); let exports = {}; if (extraForeignImports !== undefined) { @@ -1956,13 +1972,6 @@ async function runWasm(wasmPath, consoleElement, extraForeignImports, wasmMemory const dt = (currTimeStamp - prevTimeStamp)*0.001; prevTimeStamp = currTimeStamp; - while (eventQueue.length > 0) { - let e = eventQueue.shift() - event_temp.data = e.event_data; - exports.odin_dom_do_event_callback(e.data, e.callback, odin_ctx); - } - event_temp.data = null; - if (!exports.step(dt, odin_ctx)) { exports._end(); return;