Skip to content

Commit 0f21271

Browse files
authored
Add a way to remove a single event listener (#20983) (#25535)
Fixes: #20983
1 parent 87c5fbe commit 0f21271

File tree

9 files changed

+252
-2
lines changed

9 files changed

+252
-2
lines changed

ChangeLog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ See docs/process.md for more on how version tagging works.
2020

2121
4.0.20 (in development)
2222
-----------------------
23+
- Added `emscripten_html5_remove_event_listener` function in `html5.h` in order to be
24+
able to remove a single callback. (#25535)
2325
- The standalone `file_packager.py` script no longer supports `--embed` with JS
2426
output (use `--obj-output` is now required for embedding data). This usage
2527
has been producing a warning since #16050 which is now an error. (#25049)

site/source/docs/api_reference/html5.h.rst

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,54 @@ The ``useCapture`` parameter maps to ``useCapture`` in `EventTarget.addEventLis
9090

9191
Most functions return the result using the type :c:data:`EMSCRIPTEN_RESULT`. Zero and positive values denote success. Negative values signal failure. None of the functions fail or abort by throwing a JavaScript or C++ exception. If a particular browser does not support the given feature, the value :c:data:`EMSCRIPTEN_RESULT_NOT_SUPPORTED` will be returned at the time the callback is registered.
9292

93+
Unregister function
94+
-------------------
95+
96+
In order to unregister a single event handler callback, call the following function:
97+
98+
.. code-block:: cpp
99+
100+
EMSCRIPTEN_RESULT emscripten_html5_remove_event_listener(
101+
const char *target, // ID of the target HTML element.
102+
void *userData, // User-defined data (passed to the callback).
103+
int eventTypeId, // The event type ID (EMSCRIPTEN_EVENT_XXX).
104+
void *callback // Callback function.
105+
);
106+
107+
108+
The ``target``, ``userData`` and ``callback`` parameters are the same parameters provided in ``emscripten_set_some_callback`` with the only difference being that, since this function applies to all types of callbacks, the type of ``callback`` is ``void *``.
109+
110+
Note in particular that the value of ``userData`` will need to match with the call that was used to register the callback. If you are having trouble, double check the value of ``userData``.
111+
112+
The ``eventTypeId`` represents the event type, the same Id received in the callback functions.
113+
114+
The function returns ``EMSCRIPTEN_RESULT_SUCCESS`` when the event handler callback is removed and ``EMSCRIPTEN_RESULT_INVALID_PARAM`` otherwise.
115+
116+
.. code-block:: cpp
117+
118+
// Example
119+
120+
bool my_mouse_callback_1(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) {
121+
// ...
122+
}
123+
124+
bool my_mouse_callback_2(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) {
125+
// ...
126+
}
127+
128+
void main() {
129+
130+
// 1. set callbacks for mouse down and mouse move
131+
emscripten_set_mousedown_callback("#mydiv", 0, my_mouse_callback_1);
132+
emscripten_set_mousedown_callback("#mydiv", (void *) 34, my_mouse_callback_2);
133+
emscripten_set_mousemove_callback("#mydiv", 0, my_mouse_callback_1);
134+
135+
// 2. remove these callbacks
136+
emscripten_html5_remove_event_listener("#mydiv", 0, EMSCRIPTEN_EVENT_MOUSEDOWN, my_mouse_callback_1);
137+
emscripten_html5_remove_event_listener("#mydiv", (void *) 34, EMSCRIPTEN_EVENT_MOUSEDOWN, my_mouse_callback_2);
138+
emscripten_html5_remove_event_listener("#mydiv", 0, EMSCRIPTEN_EVENT_MOUSEMOVE, my_mouse_callback_1);
139+
}
140+
93141
94142
Callback functions
95143
------------------

src/lib/libhtml5.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,19 @@ var LibraryHTML5 = {
201201
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
202202
},
203203

204+
removeSingleHandler(eventHandler) {
205+
for (var [i, handler] of JSEvents.eventHandlers.entries()) {
206+
if (handler.target === eventHandler.target
207+
&& handler.eventTypeId === eventHandler.eventTypeId
208+
&& handler.callbackfunc === eventHandler.callbackfunc
209+
&& handler.userData === eventHandler.userData) {
210+
JSEvents._removeHandler(i);
211+
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
212+
}
213+
}
214+
return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}};
215+
},
216+
204217
#if PTHREADS
205218
getTargetThreadForEventCallback(targetThread) {
206219
switch (targetThread) {
@@ -291,6 +304,8 @@ var LibraryHTML5 = {
291304
var eventHandler = {
292305
target: findEventTarget(target),
293306
eventTypeString,
307+
eventTypeId,
308+
userData,
294309
callbackfunc,
295310
handlerFunc: keyEventHandlerFunc,
296311
useCapture
@@ -405,6 +420,18 @@ var LibraryHTML5 = {
405420
},
406421
#endif
407422

423+
emscripten_html5_remove_event_listener__proxy: 'sync',
424+
emscripten_html5_remove_event_listener__deps: ['$JSEvents', '$findEventTarget'],
425+
emscripten_html5_remove_event_listener: (target, userData, eventTypeId, callback) => {
426+
var eventHandler = {
427+
target: findEventTarget(target),
428+
userData,
429+
eventTypeId,
430+
callbackfunc: callback,
431+
};
432+
return JSEvents.removeSingleHandler(eventHandler);
433+
},
434+
408435
emscripten_set_keypress_callback_on_thread__proxy: 'sync',
409436
emscripten_set_keypress_callback_on_thread__deps: ['$registerKeyEventCallback'],
410437
emscripten_set_keypress_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
@@ -495,6 +522,8 @@ var LibraryHTML5 = {
495522
allowsDeferredCalls: eventTypeString != 'mousemove' && eventTypeString != 'mouseenter' && eventTypeString != 'mouseleave', // Mouse move events do not allow fullscreen/pointer lock requests to be handled in them!
496523
#endif
497524
eventTypeString,
525+
eventTypeId,
526+
userData,
498527
callbackfunc,
499528
handlerFunc: mouseEventHandlerFunc,
500529
useCapture
@@ -586,6 +615,8 @@ var LibraryHTML5 = {
586615
allowsDeferredCalls: true,
587616
#endif
588617
eventTypeString,
618+
eventTypeId,
619+
userData,
589620
callbackfunc,
590621
handlerFunc: wheelHandlerFunc,
591622
useCapture
@@ -658,6 +689,8 @@ var LibraryHTML5 = {
658689
var eventHandler = {
659690
target,
660691
eventTypeString,
692+
eventTypeId,
693+
userData,
661694
callbackfunc,
662695
handlerFunc: uiEventHandlerFunc,
663696
useCapture
@@ -702,6 +735,8 @@ var LibraryHTML5 = {
702735
var eventHandler = {
703736
target: findEventTarget(target),
704737
eventTypeString,
738+
eventTypeId,
739+
userData,
705740
callbackfunc,
706741
handlerFunc: focusEventHandlerFunc,
707742
useCapture
@@ -759,6 +794,8 @@ var LibraryHTML5 = {
759794
var eventHandler = {
760795
target: findEventTarget(target),
761796
eventTypeString,
797+
eventTypeId,
798+
userData,
762799
callbackfunc,
763800
handlerFunc: deviceOrientationEventHandlerFunc,
764801
useCapture
@@ -827,6 +864,8 @@ var LibraryHTML5 = {
827864
var eventHandler = {
828865
target: findEventTarget(target),
829866
eventTypeString,
867+
eventTypeId,
868+
userData,
830869
callbackfunc,
831870
handlerFunc: deviceMotionEventHandlerFunc,
832871
useCapture
@@ -907,6 +946,8 @@ var LibraryHTML5 = {
907946
var eventHandler = {
908947
target,
909948
eventTypeString,
949+
eventTypeId,
950+
userData,
910951
callbackfunc,
911952
handlerFunc: orientationChangeEventHandlerFunc,
912953
useCapture
@@ -1014,6 +1055,8 @@ var LibraryHTML5 = {
10141055
var eventHandler = {
10151056
target,
10161057
eventTypeString,
1058+
eventTypeId,
1059+
userData,
10171060
callbackfunc,
10181061
handlerFunc: fullscreenChangeEventhandlerFunc,
10191062
useCapture
@@ -1512,6 +1555,8 @@ var LibraryHTML5 = {
15121555
var eventHandler = {
15131556
target,
15141557
eventTypeString,
1558+
eventTypeId,
1559+
userData,
15151560
callbackfunc,
15161561
handlerFunc: pointerlockChangeEventHandlerFunc,
15171562
useCapture
@@ -1556,6 +1601,8 @@ var LibraryHTML5 = {
15561601
var eventHandler = {
15571602
target,
15581603
eventTypeString,
1604+
eventTypeId,
1605+
userData,
15591606
callbackfunc,
15601607
handlerFunc: pointerlockErrorEventHandlerFunc,
15611608
useCapture
@@ -1706,6 +1753,8 @@ var LibraryHTML5 = {
17061753
var eventHandler = {
17071754
target,
17081755
eventTypeString,
1756+
eventTypeId,
1757+
userData,
17091758
callbackfunc,
17101759
handlerFunc: visibilityChangeEventHandlerFunc,
17111760
useCapture
@@ -1821,6 +1870,8 @@ var LibraryHTML5 = {
18211870
allowsDeferredCalls: eventTypeString == 'touchstart' || eventTypeString == 'touchend',
18221871
#endif
18231872
eventTypeString,
1873+
eventTypeId,
1874+
userData,
18241875
callbackfunc,
18251876
handlerFunc: touchEventHandlerFunc,
18261877
useCapture
@@ -1904,6 +1955,8 @@ var LibraryHTML5 = {
19041955
allowsDeferredCalls: true,
19051956
#endif
19061957
eventTypeString,
1958+
eventTypeId,
1959+
userData,
19071960
callbackfunc,
19081961
handlerFunc: gamepadEventHandlerFunc,
19091962
useCapture
@@ -1990,6 +2043,8 @@ var LibraryHTML5 = {
19902043
var eventHandler = {
19912044
target: findEventTarget(target),
19922045
eventTypeString,
2046+
eventTypeId,
2047+
userData,
19932048
callbackfunc,
19942049
handlerFunc: beforeUnloadEventHandlerFunc,
19952050
useCapture
@@ -2040,6 +2095,8 @@ var LibraryHTML5 = {
20402095
var eventHandler = {
20412096
target: battery,
20422097
eventTypeString,
2098+
eventTypeId,
2099+
userData,
20432100
callbackfunc,
20442101
handlerFunc: batteryEventHandlerFunc,
20452102
useCapture

src/lib/libhtml5_webgl.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,8 @@ var LibraryHtml5WebGL = {
440440
var eventHandler = {
441441
target: findEventTarget(target),
442442
eventTypeString,
443+
eventTypeId,
444+
userData,
443445
callbackfunc,
444446
handlerFunc: webGlEventHandlerFunc,
445447
useCapture

src/lib/libsigs.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,7 @@ sigs = {
666666
emscripten_has_threading_support__sig: 'i',
667667
emscripten_hide_mouse__sig: 'v',
668668
emscripten_html5_remove_all_event_listeners__sig: 'v',
669+
emscripten_html5_remove_event_listener__sig: 'ippip',
669670
emscripten_idb_async_clear__sig: 'vpppp',
670671
emscripten_idb_async_delete__sig: 'vppppp',
671672
emscripten_idb_async_exists__sig: 'vppppp',

system/include/emscripten/html5.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,8 @@ EMSCRIPTEN_RESULT emscripten_get_element_css_size(const char *target __attribute
420420

421421
void emscripten_html5_remove_all_event_listeners(void);
422422

423+
EMSCRIPTEN_RESULT emscripten_html5_remove_event_listener(const char *target __attribute__((nonnull)), void *userData, int eventTypeId, void *callback __attribute__((nonnull)));
424+
423425
#define EM_CALLBACK_THREAD_CONTEXT_MAIN_RUNTIME_THREAD ((pthread_t)0x1)
424426
#define EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD ((pthread_t)0x2)
425427

test/codesize/test_codesize_hello_dylink_all.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"a.out.js": 245421,
2+
"a.out.js": 245799,
33
"a.out.nodebug.wasm": 574167,
4-
"total": 819588,
4+
"total": 819966,
55
"sent": [
66
"IMG_Init",
77
"IMG_Load",
@@ -681,6 +681,7 @@
681681
"emscripten_has_asyncify",
682682
"emscripten_hide_mouse",
683683
"emscripten_html5_remove_all_event_listeners",
684+
"emscripten_html5_remove_event_listener",
684685
"emscripten_idb_async_clear",
685686
"emscripten_idb_async_delete",
686687
"emscripten_idb_async_exists",

test/test_browser.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2675,6 +2675,9 @@ def test_html5_core(self, opts):
26752675
self.cflags.append('--pre-js=pre.js')
26762676
self.btest_exit('test_html5_core.c', cflags=opts)
26772677

2678+
def test_html5_remove_event_listener(self):
2679+
self.btest_exit('test_html5_remove_event_listener.c')
2680+
26782681
@parameterized({
26792682
'': ([],),
26802683
'closure': (['-O2', '-g1', '--closure=1'],),

0 commit comments

Comments
 (0)