eventListener doesn't fire when the last focused element was a type field and the layout is japanese

Hello, I have a template where all elements can be navigated with keyboard and the mouse click is simulated by pressing ‘z’ key.
When I switch focus with tab from type field to button and press ‘z’ and the layout is english, the button works. When I switch focus from some element to button and press ‘z’ and the layout is japanese, it also works. But when I switch focus from type field to button, press ‘z’ and the layout is japanese, it doesn’t work and switches the focus back to input field instead. So, it works at all times but when the last element in focus was a type field and the layout is set to japanese (or chinese or korean).
From my attempts to fix this I found out that with non english layout eventListener doesn’t fire at all (but again, it does fire when the last element in focus was not a type field).

Not sure if the reason for this problem is in the IME or anki.

The following code works in the browser (the button works on ‘z’ keypress after switching focus from type field), but doesn’t in anki:

<!DOCTYPE html>
<html lang="en">
<head>
  <title>eventlistener</title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<style>
body >* {
  font-size: 30px;
  margin: 10px;
}
#text {
  border: 2px solid aqua;
}
</style>
<div contenteditable="true" tabindex="0" id="typefield"></div>
<div tabindex ="0" id="button">button</div>
<div tabindex ="0" id="text">some text</div>
<script>
// click by pressing z
document.addEventListener('keydown', function(event) {
  if (event.keyCode == 90) {
    event.target.click();
    console.log("z pressed");
  }
});
// toggle border color on button click
document.getElementById("button").addEventListener('click', function (event) {
  var text = document.getElementById("text");
  text.style.border = text.style.border == "2px solid red" ? "2px solid aqua" : "2px solid red";
});
</script>
</body>
</html>

I tried to come up with some workarounds, like adding an eventListener for all input types (input, beforeinput, keydown, keyup, keypress) that would prevent default behavior if active element is not a type field, which didn’t work (but did work in the browser). So, I guess eventListener just doesn’t work if the layout is japanese and the last element in focus was a type field?

Would appreciate any leads
Thank you!

Not sure if I explained clearly so here is a screen recording where I first press the button with english layout and then do the same but with japanese layout:

1 Like

Not sure if it addresses the original problem you are trying to solve, but for IME inputs, you can listen for compositionupdate events. Unlike keypresses, they don’t carry key codes directly, so you’ll have to discern them from event.data, like

event.data.slice(-1) === "z"
1 Like

Thank you for the reply!! (: I think I found the solution I’m happy with. Turns out it was firing composition events instead of keypresses. preventDefault doesnt cancel ‘compositionstart’ though, but luckily I’ve found a workaround here: javascript - How can I reliably cancel a compositionstart event? - Stack Overflow.

document.addEventListener('compositionstart', function(event) {
 if (event.target != document.getElementById("typefield")) {
   event.target.blur();
   setTimeout(() => event.target.focus(), 0);
 }
});

Now one just has to press z key two times: one so it cancels the input, and the second time so it finally fires the keypress event. Much better than tab, tab, shift+tab, z.

Though it’s still interesting why it worked in the browser as is, different browser engines or something?

Can’t the required callback for the keypress event be included into the compositionstart listener so that pressing z only once would be enough?

Not gonna lie I don’t understand what adding a callback into the compositionstart listener exactly means, but your reply made me look at the events being fired - which were just compositionstart and keyup, so changing the event type from keydown to keyup (in the eventListener that dispatches clicks) was enough to make it work

1 Like

What I meant is just adding anything you want to do inside the compositionstart listener you pasted above. So that it would be self-sufficient and do the same thing the original keydown listener does after adjusting the focus. Might still be worth considering, because keydown events have a bit more responsive feel to them than keyup events. Although it is not at all important, if everything works for you in the current implementation.

Ah yes, but I’m not sure if it’s possible to make it self sufficient since it returns an empty string in event.data?
And honestly the delay before keyup fires is close to unnoticeable, so the current solution is already good enough

In my tests, at least, it was returning the current string being typed in IME. Maybe that’s because I used compositionupdate event instead. Or maybe it just depends on the IME itself.

Yes, compositionupdate returns typed characters for me as well. But the thing is, this event doesn’t fire when focus is on the button; only compositionstart and keyup fire, so keyup is the only way to retrieve the typed key, I guess

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.