@@ -1341,11 +1341,33 @@ void Emscripten_RegisterEventHandlers(SDL_WindowData *data)
13411341
13421342 keyElement = Emscripten_GetKeyboardTargetElement (data -> keyboard_element );
13431343 if (keyElement ) {
1344+ // Emscripten's HTML5 helpers do not deduplicate `addEventListener` calls:
1345+ // see `registerOrRemoveHandler` in `emscripten/src/lib/libhtml5.js`.
1346+ //
1347+ // If a previous SDL window already registered keyboard handlers on the same
1348+ // target, the new registration would *stack* a second listener, causing every
1349+ // browser keydown to fire `Emscripten_HandleKey` twice.
1350+ //
1351+ // The duplicate calls then produce two `SDL_EVENT_KEY_DOWN` events per physical
1352+ // keypress (the second one with `repeat=true`, due to the keystate-based repeat
1353+ // detection in `SDL_SendKeyboardKeyInternal`).
1354+ //
1355+ // We must clear any prior handler on this target before installing ours:
1356+ emscripten_set_keydown_callback (keyElement , NULL , 0 , NULL );
1357+ emscripten_set_keyup_callback (keyElement , NULL , 0 , NULL );
1358+ emscripten_set_keypress_callback (keyElement , NULL , 0 , NULL );
1359+
13441360 MAIN_THREAD_EM_ASM_INT ({
13451361 var data = $0 ;
13461362 // our keymod state can get confused in various ways (changed capslock when browser didn't have focus, etc), and you can't query the current
13471363 // state from the DOM, outside of a keyboard event, so catch keypresses globally and reset mod state if it's unexpectedly wrong. Best we can do.
13481364 // Note that this thing _only_ adjusts the lock keys if necessary; the real SDL keypress handling happens elsewhere.
1365+
1366+ // Remove any prior listener first -- `addEventListener` does not deduplicate either.
1367+ if (document .sdlEventHandlerLockKeysCheck ) {
1368+ document .removeEventListener ("keydown" , document .sdlEventHandlerLockKeysCheck );
1369+ }
1370+
13491371 document .sdlEventHandlerLockKeysCheck = function (event ) {
13501372 // don't try to adjust the state on the actual lock key presses; the normal key handler will catch that and adjust.
13511373 if ((event .key != "CapsLock" ) && (event .key != "NumLock" ) && (event .key != "ScrollLock" ))
0 commit comments