New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

shell: allow keyboard refocus when embedded in an iframe #7631

Open
wants to merge 1 commit into
base: incoming
from

Conversation

Projects
None yet
2 participants
@Beuc
Copy link
Contributor

Beuc commented Dec 8, 2018

Hi,

On sites such as itch.io, the game area is embedded in an iframe.
Clicking on outer webpage makes the game lose keyboard focus, but clicking on the game doesn't restore it.

#7484 does not help in that case: clicking on the canvas doesn't change the focus. For a SDL2 application, finding a bit of non-canvas document area to click on is a work-around, but not suitable if the canvas auto-adjusts to the document area.

I added 2 custom events to the canvas to fix keyboard focus:

  • restore window focus on mouseenter
  • restore window focus also on click, since mouseenter is not triggered in all situations (e.g. at the end of a selection event that starts in the outer document and that ends with the mouse on the canvas)

This is an issue that is common on such websites, and tricky to identify and fix, hence why I submit it here. If this is too specific, let me know if there's an other way to address this issue :)

@kripken

This comment has been minimized.

Copy link
Member

kripken commented Dec 11, 2018

#7484 does not help in that case: clicking on the canvas doesn't change the focus.

Interesting, why not? is it something special about iframes?

@Beuc

This comment has been minimized.

Copy link
Contributor

Beuc commented Dec 11, 2018

What's special about iframes is the ability to lose the focus to the parent page :)
In SDL2 the keyboard events are captured by the window (by default), so in a single page focus is kept at all times.

@kripken

This comment has been minimized.

Copy link
Member

kripken commented Dec 11, 2018

Sorry if it's a silly question :) - why do iframes lose their focus here? Is the main page intentionally stealing the focus on these sites? (it seems like otherwise if an iframe is clicked on, it should receive focus?)

@Beuc

This comment has been minimized.

Copy link
Contributor

Beuc commented Dec 11, 2018

The user loses the focus when e.g. they click on the outer document.

In an ideal world, the iframe should get focus back when clicked on.
But it doesn't when you click on the canvas.
(it does when you click in the iframe but not in the canvas)

@kripken

This comment has been minimized.

Copy link
Member

kripken commented Dec 12, 2018

I may be missing something here - I can't reproduce that behavior in a testcase. For example, in a.html put this:

<iframe src="b.html" width=1000 height=1000></iframe>

and in b.html put this:

<canvas tabindex=-1 id="canvas" width=500 height=500 onfocus="console.log('canvas is focused')" style="background-color: black"></canvas>
<hr>
hi
<hr>
<script>
setInterval(function() {
  console.log(document.activeElement === document.getElementById('canvas'));
}, 1000);
</script>

Then clicking on the canvas in the iframe does focus the element as I would expect. Is this testcase different from what you are seeing in a crucial way?

@Beuc

This comment has been minimized.

Copy link
Contributor

Beuc commented Dec 12, 2018

The difference appears to come from SDL2 and handling mouse events (default), which can be simulated in your test case with:

document.getElementById('canvas').addEventListener("mousedown", function(e) { e.preventDefault(); });

e.preventDefault() is used in a lot of SDL2 event handlers emscripten_set_xxx_callback to prevent browser behavior, see e.g. emscripten-ports/SDL2#64 .
In this particular case I'm not sure of the specifics, but to the least it prevents the browser from adding a small "selected" dashed border to the canvas when clicked on (ugly ;)).
@Daft-Freak may know more about it :)

Still with e.preventDefault:

  • Clicking on the canvas doesn't restore keyboard focus.
  • Clicking on the inner document dodging the canvas restores keyboard focus.

Note that in this configuration, document.activeElement is "body" at all times.

This is messier than I initially though, I'm not sure adding a counter-handler is a clean fix.
Or perhaps this is to be done in library_html5.js.
Thoughts?

@kripken

This comment has been minimized.

Copy link
Member

kripken commented Dec 14, 2018

Thanks, yeah, makes sense preventDefault could cause this. I think we have it because otherwise say pressing the down button will also scroll the page, not just tell the game "player pressed down".

What I think maybe we should do is that in such handlers that preventDefault, we can also set the focus. Although I'm not sure if that's better or not than adding another handler as this PR does. It may be cleaner though since then it's just in the code that needs it (and not in the HTML page for all possible applications). If we think that makes sense, perhaps in the html5 library code would be the proper place for this, but I'm not sure offhand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment